From 34196c06760ff394b44cc1d091545133a541069f Mon Sep 17 00:00:00 2001 From: Nico Hinderling Date: Thu, 11 Dec 2025 11:46:18 -0800 Subject: [PATCH 01/19] Save PDFs and SVGs with content hash (#3024) Related to https://linear.app/getsentry/issue/EME-550/ios-insights-duplicate-files Write PDF/SVG raw data to disk during asset catalog parsing to enable duplicate detection of SVG and pdf files --- .../AssetCatalogReader.swift | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift b/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift index aa6014fb70..6d12ac7443 100644 --- a/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift +++ b/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift @@ -1,4 +1,5 @@ import CoreGraphics +import CryptoKit import Foundation import ImageIO import UniformTypeIdentifiers @@ -40,6 +41,7 @@ struct AssetCatalogEntry: Encodable { let type: AssetType? let idiom: String? let colorspace: String? + let contentHash: String? } enum Error: Swift.Error { @@ -112,7 +114,7 @@ enum AssetUtil { let (structuredThemeStore, assetKeys) = initializeCatalog(from: file) - var images: [String: (cgImage: CGImage, format: String)] = [:] + var cgImages: [String: (cgImage: CGImage, format: String)] = [:] // First pass: Build map of multisize sets and cache renditions for performance var multisizeSets: [MultisizeSetInfo] = [] @@ -216,6 +218,7 @@ enum AssetUtil { var width: Int? var height: Int? var unslicedImage: CGImage? + var contentHash: String? = nil if isMultisizeImageSet { continue @@ -223,10 +226,15 @@ enum AssetUtil { // Get image dimensions from regular rendition (width, height, unslicedImage) = resolveImageDimensions(rendition, isVector) - // Skip SVGs, but save images even if they don't have an extension (default to png) - if fileExtension != "svg", let unslicedImage = unslicedImage { + // Compute content hash for PDFs/SVGs without saving to disk + if fileExtension == "pdf" || fileExtension == "svg" { + // Hash PDFs/SVGs in-memory (Python can't access _srcData without parsing binary .car format) + contentHash = data.sha256Hash() + } + // Save images that can be converted to CGImage (excluding PDFs/SVGs) + else if let unslicedImage = unslicedImage { let format = fileExtension.isEmpty ? "png" : fileExtension - images[imageId] = (cgImage: unslicedImage, format: format) + cgImages[imageId] = (cgImage: unslicedImage, format: format) } } @@ -251,7 +259,8 @@ enum AssetUtil { filename: renditionTypeName, type: assetType, idiom: idiomToString(idiomValue), - colorspace: colorSpaceIDToString(colorSpaceID) + colorspace: colorSpaceIDToString(colorSpaceID), + contentHash: contentHash ) assets.append(asset) } @@ -266,7 +275,8 @@ enum AssetUtil { filename: nil, type: nil, idiom: nil, - colorspace: nil + colorspace: nil, + contentHash: nil )) let data = try! JSONEncoder().encode(assets) @@ -275,7 +285,7 @@ enum AssetUtil { .appendingPathComponent("Assets") .appendingPathExtension("json") try! data.write(to: url, options: []) - for (id, imageInfo) in images { + for (id, imageInfo) in cgImages { let format = imageInfo.format let cgImage = imageInfo.cgImage let fileURL = folder.appendingPathComponent(id).appendingPathExtension(format) @@ -460,6 +470,17 @@ enum AssetUtil { } } +private extension Data { + func sha256Hash() -> String { + if #available(macOS 10.15, *) { + let digest = SHA256.hash(data: self) + return digest.map { String(format: "%02x", $0) }.joined() + } + // Fallback for older macOS (shouldn't happen with version 13+ requirement) + return "" + } +} + private extension NSObject { func getUInt(forKey key: String) -> UInt? { if let result = perform(Selector(key)) { From 9c83c3ef6cd83d1306db702d8486887cd72e2101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Peer=20St=C3=B6cklmair?= Date: Fri, 12 Dec 2025 11:18:39 +0100 Subject: [PATCH 02/19] fix: Use node directly in the postinstall script (#3030) (closes #3028) (closes [CLI-247](https://linear.app/getsentry/issue/CLI-247/version-2583-includes-a-postinstall-script-that-is-incompatible-with)) This fixes the postinstall scripts for package managers other than NPM. --------- Co-authored-by: Daniel Szoke <7881302+szokeasaurusrex@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e28e4f3f5..c8e5934417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Use node directly in the postinstall script, instead of using `npm run` ([#3030](https://github.com/getsentry/sentry-cli/pull/3030)). This change ensures the postinstall script remains compatible with package managers other than `npm`. + ## 2.58.3 ### Improvements diff --git a/package.json b/package.json index 89c9bdd2d9..08e6f64334 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@sentry/cli-win32-arm64": "2.58.3" }, "scripts": { - "postinstall": "npm run install-cli", + "postinstall": "node ./scripts/install.js", "build": "tsc", "install-cli": "node ./scripts/install.js", "prepack": "npm run build", From 3e6a4262991e783abd8cd7e52e45f525854c486f Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 12 Dec 2025 10:27:46 +0000 Subject: [PATCH 03/19] release: 2.58.4 --- CHANGELOG.md | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- npm-binary-distributions/darwin/package.json | 2 +- .../linux-arm/package.json | 2 +- .../linux-arm64/package.json | 2 +- .../linux-i686/package.json | 2 +- .../linux-x64/package.json | 2 +- .../win32-arm64/package.json | 2 +- .../win32-i686/package.json | 2 +- .../win32-x64/package.json | 2 +- package-lock.json | 2 +- package.json | 18 +++++++++--------- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e5934417..a774282122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 2.58.4 ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 617b6d650b..22fb4c31b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2726,7 +2726,7 @@ dependencies = [ [[package]] name = "sentry-cli" -version = "2.58.3" +version = "2.58.4" dependencies = [ "anyhow", "anylog", diff --git a/Cargo.toml b/Cargo.toml index c99979b13d..a682fd89d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] build = "build.rs" name = "sentry-cli" -version = "2.58.3" +version = "2.58.4" edition = "2021" rust-version = "1.91" diff --git a/npm-binary-distributions/darwin/package.json b/npm-binary-distributions/darwin/package.json index 1db22057cc..05e118615d 100644 --- a/npm-binary-distributions/darwin/package.json +++ b/npm-binary-distributions/darwin/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-darwin", - "version": "2.58.3", + "version": "2.58.4", "description": "The darwin distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/linux-arm/package.json b/npm-binary-distributions/linux-arm/package.json index 8dbd8888f7..976e002805 100644 --- a/npm-binary-distributions/linux-arm/package.json +++ b/npm-binary-distributions/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-linux-arm", - "version": "2.58.3", + "version": "2.58.4", "description": "The linux arm distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/linux-arm64/package.json b/npm-binary-distributions/linux-arm64/package.json index 68b55fdeaf..3c39d9f763 100644 --- a/npm-binary-distributions/linux-arm64/package.json +++ b/npm-binary-distributions/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-linux-arm64", - "version": "2.58.3", + "version": "2.58.4", "description": "The linux arm64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/linux-i686/package.json b/npm-binary-distributions/linux-i686/package.json index 8aa459a6b6..e34919f39e 100644 --- a/npm-binary-distributions/linux-i686/package.json +++ b/npm-binary-distributions/linux-i686/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-linux-i686", - "version": "2.58.3", + "version": "2.58.4", "description": "The linux x86 and ia32 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/linux-x64/package.json b/npm-binary-distributions/linux-x64/package.json index 4b93201845..663b8bdfcf 100644 --- a/npm-binary-distributions/linux-x64/package.json +++ b/npm-binary-distributions/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-linux-x64", - "version": "2.58.3", + "version": "2.58.4", "description": "The linux x64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/win32-arm64/package.json b/npm-binary-distributions/win32-arm64/package.json index a744cdf484..413bac58a2 100644 --- a/npm-binary-distributions/win32-arm64/package.json +++ b/npm-binary-distributions/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-win32-arm64", - "version": "2.58.3", + "version": "2.58.4", "description": "The windows arm64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/win32-i686/package.json b/npm-binary-distributions/win32-i686/package.json index 9e702ec288..ab7f6b3ac2 100644 --- a/npm-binary-distributions/win32-i686/package.json +++ b/npm-binary-distributions/win32-i686/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-win32-i686", - "version": "2.58.3", + "version": "2.58.4", "description": "The windows x86 and ia32 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/npm-binary-distributions/win32-x64/package.json b/npm-binary-distributions/win32-x64/package.json index ebae3c65e8..164434fd9b 100644 --- a/npm-binary-distributions/win32-x64/package.json +++ b/npm-binary-distributions/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli-win32-x64", - "version": "2.58.3", + "version": "2.58.4", "description": "The windows x64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "FSL-1.1-MIT", diff --git a/package-lock.json b/package-lock.json index bed412ec14..998903e076 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli", - "version": "2.58.3", + "version": "2.58.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 08e6f64334..5fb18d3d09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli", - "version": "2.58.3", + "version": "2.58.4", "description": "A command line utility to work with Sentry. https://docs.sentry.io/hosted/learn/cli/", "repository": "git://github.com/getsentry/sentry-cli.git", "homepage": "https://docs.sentry.io/hosted/learn/cli/", @@ -32,14 +32,14 @@ "typescript": "5.8.3" }, "optionalDependencies": { - "@sentry/cli-darwin": "2.58.3", - "@sentry/cli-linux-arm": "2.58.3", - "@sentry/cli-linux-arm64": "2.58.3", - "@sentry/cli-linux-i686": "2.58.3", - "@sentry/cli-linux-x64": "2.58.3", - "@sentry/cli-win32-i686": "2.58.3", - "@sentry/cli-win32-x64": "2.58.3", - "@sentry/cli-win32-arm64": "2.58.3" + "@sentry/cli-darwin": "2.58.4", + "@sentry/cli-linux-arm": "2.58.4", + "@sentry/cli-linux-arm64": "2.58.4", + "@sentry/cli-linux-i686": "2.58.4", + "@sentry/cli-linux-x64": "2.58.4", + "@sentry/cli-win32-i686": "2.58.4", + "@sentry/cli-win32-x64": "2.58.4", + "@sentry/cli-win32-arm64": "2.58.4" }, "scripts": { "postinstall": "node ./scripts/install.js", From 3eb2a95362e33a2854f4688fe104aafbc39552c1 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 12 Dec 2025 10:38:15 +0000 Subject: [PATCH 04/19] =?UTF-8?q?build(npm):=20=F0=9F=A4=96=20Bump=20optio?= =?UTF-8?q?nal=20dependencies=20to=202.58.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 998903e076..81cf102f14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -767,51 +767,51 @@ } }, "@sentry/cli-darwin": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.58.3.tgz", - "integrity": "sha512-4bnI5e07cVkG3DdTPpBJcoRjwHvf8GPCY/vBH6gGTrM+cXxGgk7jiZpkblq1ZvpW5H51mFjiO5qqMO7GNjstQA==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.58.4.tgz", + "integrity": "sha512-kbTD+P4X8O+nsNwPxCywtj3q22ecyRHWff98rdcmtRrvwz8CKi/T4Jxn/fnn2i4VEchy08OWBuZAqaA5Kh2hRQ==", "optional": true }, "@sentry/cli-linux-arm": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.58.3.tgz", - "integrity": "sha512-33mlrULHtxK5rjzO7YJDtXyOeMTpkZOgfcQqcjyxeDY91jSCXE0EhlBV6SGCKqvahmvh9RUgINLkQO+qc2OjDg==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.58.4.tgz", + "integrity": "sha512-rdQ8beTwnN48hv7iV7e7ZKucPec5NJkRdrrycMJMZlzGBPi56LqnclgsHySJ6Kfq506A2MNuQnKGaf/sBC9REA==", "optional": true }, "@sentry/cli-linux-arm64": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.58.3.tgz", - "integrity": "sha512-xpn94gpy8U+JwsY4Eamlx/gNXh5YiZTmA1XT73kOUBrLs+e+qwQh6gfnzGxx7wdX9x+CJooTw8rwP4unisGALQ==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.58.4.tgz", + "integrity": "sha512-0g0KwsOozkLtzN8/0+oMZoOuQ0o7W6O+hx+ydVU1bktaMGKEJLMAWxOQNjsh1TcBbNIXVOKM/I8l0ROhaAb8Ig==", "optional": true }, "@sentry/cli-linux-i686": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.58.3.tgz", - "integrity": "sha512-Z4qWllBAPa0Z3nO3cvw9bTIfASxo5EYjnid7MvWB99TKUTdd2+YCIJ9rP9UadZqvOE9AekF+DHdh35j9E1urOQ==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.58.4.tgz", + "integrity": "sha512-NseoIQAFtkziHyjZNPTu1Gm1opeQHt7Wm1LbLrGWVIRvUOzlslO9/8i6wETUZ6TjlQxBVRgd3Q0lRBG2A8rFYA==", "optional": true }, "@sentry/cli-linux-x64": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.58.3.tgz", - "integrity": "sha512-i68RTLedYzxZ+wdh9JS8aeMCWbnJq4xYa3Rmib2lrQ9AvScBLJlFbafjYnZUy9PWiqc78PFJc5gLefPRDpIexw==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.58.4.tgz", + "integrity": "sha512-d3Arz+OO/wJYTqCYlSN3Ktm+W8rynQ/IMtSZLK8nu0ryh5mJOh+9XlXY6oDXw4YlsM8qCRrNquR8iEI1Y/IH+Q==", "optional": true }, "@sentry/cli-win32-arm64": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.58.3.tgz", - "integrity": "sha512-en2uDEi+NLEVCfTvuivKxUSSe2jp3iKtSRFSONSRMc0p7O6SlGYflPZCVIGPXQWKSNYXdQINbefQND4d5bPzsQ==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.58.4.tgz", + "integrity": "sha512-bqYrF43+jXdDBh0f8HIJU3tbvlOFtGyRjHB8AoRuMQv9TEDUfENZyCelhdjA+KwDKYl48R1Yasb4EHNzsoO83w==", "optional": true }, "@sentry/cli-win32-i686": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.58.3.tgz", - "integrity": "sha512-dYWNuE+FtZXpT4aqW68/4ah2WAAz//QSQxxpuTBAQ+Wui26Mp30q5nJdYOzAckdSF8yVKjIHB0NLuIYZYHijyQ==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.58.4.tgz", + "integrity": "sha512-3triFD6jyvhVcXOmGyttf+deKZcC1tURdhnmDUIBkiDPJKGT/N5xa4qAtHJlAB/h8L9jgYih9bvJnvvFVM7yug==", "optional": true }, "@sentry/cli-win32-x64": { - "version": "2.58.3", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.58.3.tgz", - "integrity": "sha512-D1qkHE2Mkfu9w1zyZt8M/V+yqoycJFEtp4hCv/HtLhExNtZYrdjf8LHzR0tUvEBS4Y1aw4wbox+Wh8ToOhcXbQ==", + "version": "2.58.4", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.58.4.tgz", + "integrity": "sha512-cSzN4PjM1RsCZ4pxMjI0VI7yNCkxiJ5jmWncyiwHXGiXrV1eXYdQ3n1LhUYLZ91CafyprR0OhDcE+RVZ26Qb5w==", "optional": true }, "@sinonjs/commons": { From 2fcff4317465935fce02555fc0d941ba8026ca0d Mon Sep 17 00:00:00 2001 From: Daniel Szoke <7881302+szokeasaurusrex@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:09:39 +0100 Subject: [PATCH 05/19] chore(npm): Remove `install-cli` script (#3032) See https://github.com/getsentry/sentry-cli/pull/3030/changes#r2613671595 --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 5fb18d3d09..e31e9c0b60 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "scripts": { "postinstall": "node ./scripts/install.js", "build": "tsc", - "install-cli": "node ./scripts/install.js", "prepack": "npm run build", "fix": "npm-run-all fix:eslint fix:prettier", "fix:eslint": "eslint --fix bin/* scripts/**/*.js lib/**/*.js", From b9001c5705c7b43af8f154056ead22b032a5cc00 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Thu, 11 Dec 2025 16:02:08 +0100 Subject: [PATCH 06/19] docs(readme): Set minimum self-hosted version (#3027) ### Description Set minimum supported self-hosted version, and add this to README. ### Issues - Resolves #3026 - Resolves [CLI-246](https://linear.app/getsentry/issue/CLI-246/mention-minimum-supported-self-hosted-version-in-readme) --- CHANGELOG.md | 6 ++++++ README.md | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a774282122..76d98843d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### New Sentry Support Policy + +`sentry-cli` 3.0.0 and above only officially supports Sentry SaaS and Sentry self-hosted versions [25.11.1](https://github.com/getsentry/sentry/releases/tag/25.11.1) and higher. While many Sentry CLI features may, in practice, continue working with some older Sentry versions, continued support for Sentry versions older than 25.11.1 is not guaranteed. Changes which break support for Sentry versions below 25.11.1 may occur in minor or patch releases. + ## 2.58.4 ### Fixes diff --git a/README.md b/README.md index 344d826097..284608425a 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,23 @@ Sentry CLI can be used for many tasks, including uploading debug symbols and sou Please refer to [Sentry CLI's documentation page](https://docs.sentry.io/cli/). +## Compatibility + +Sentry CLI officially supports [Sentry SaaS](https://sentry.io/) and [Sentry Self-Hosted](https://github.com/getsentry/self-hosted) versions 25.11.1 and above. + +### Self-Hosted Sentry + +Although some Sentry CLI features may work with versions of Sentry Self-Hosted prior to 25.11.1, we recommend users upgrade their self-hosted installations to a compatible version. + +For users who cannot upgrade their self-hosted installation, we recommend using the latest compatible Sentry CLI version, per the table below: + +| **Sentry Self-Hosted Version** | **Newest Compatible Sentry CLI Version** | +| ------------------------------ | --------------------------------------------------------------------- | +| ≥ 25.11.1 | [latest](https://github.com/getsentry/sentry-cli/releases/latest) | +| < 25.11.1 | [2.58.4](https://github.com/getsentry/sentry-cli/releases/tag/2.58.4) | + +Note that we can only provide support for officially-supported Sentry Self-Hosted versions. We will not backport fixes for older Sentry CLI versions, even if they should be compatible with your self-hosted version. + ## Compiling In case you want to compile this yourself, you need to install at minimum the From 8d0d3f2a20c3bcb853fa1afd95bd8f457ed25867 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 28 Oct 2025 14:59:05 +0100 Subject: [PATCH 07/19] feat(proguard): Remove release association arguments (#2876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ **Breaking change:** Do not merge until ready to release in a major. Remove the `--app-id`, `--version`, and `--version-code` arguments to the `sentry-cli upload-proguard` command. Users currently using these arguments should simply stop using them. With this change, we also no longer wait for assembly of the mapping to finish on the backend; previously we needed to wait to associate the release. This change also removes any code that had been called when these flags were specified. - Resolves #2868 - Resolves [CLI-197](https://linear.app/getsentry/issue/CLI-197/remove-flags-for-setting-release) --- CHANGELOG.md | 4 + src/api/mod.rs | 36 -------- src/commands/upload_proguard.rs | 88 ------------------- src/utils/proguard/upload.rs | 10 +-- .../upload_proguard-help.trycmd | 8 +- tests/integration/upload_proguard.rs | 75 +--------------- 6 files changed, 13 insertions(+), 208 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d98843d9..5e21dcd7b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ `sentry-cli` 3.0.0 and above only officially supports Sentry SaaS and Sentry self-hosted versions [25.11.1](https://github.com/getsentry/sentry/releases/tag/25.11.1) and higher. While many Sentry CLI features may, in practice, continue working with some older Sentry versions, continued support for Sentry versions older than 25.11.1 is not guaranteed. Changes which break support for Sentry versions below 25.11.1 may occur in minor or patch releases. +### Breaking Changes + +- Removed the `upload-proguard` subcommand's `--app-id`, `--version`, and `--version-code` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. + ## 2.58.4 ### Fixes diff --git a/src/api/mod.rs b/src/api/mod.rs index 418d17749c..2778a2a364 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1059,36 +1059,6 @@ impl<'a> AuthenticatedApi<'a> { .convert_rnf(ApiErrorKind::ProjectNotFound) } - pub fn associate_proguard_mappings( - &self, - org: &str, - project: &str, - data: &AssociateProguard, - ) -> ApiResult<()> { - let path = format!( - "/projects/{}/{}/files/proguard-artifact-releases", - PathArg(org), - PathArg(project) - ); - let resp: ApiResponse = self - .request(Method::Post, &path)? - .with_json_body(data)? - .send()?; - if resp.status() == 201 { - Ok(()) - } else if resp.status() == 409 { - info!( - "Release association for release '{}', UUID '{}' already exists.", - data.release_name, data.proguard_uuid - ); - Ok(()) - } else if resp.status() == 404 { - Err(ApiErrorKind::ResourceNotFound.into()) - } else { - resp.convert() - } - } - /// List all organizations associated with the authenticated token /// in the given `Region`. If no `Region` is provided, we assume /// we're issuing a request to a monolith deployment. @@ -2246,12 +2216,6 @@ impl DebugInfoFile { } } -#[derive(Debug, Serialize)] -pub struct AssociateProguard { - pub release_name: String, - pub proguard_uuid: String, -} - #[derive(Deserialize)] struct MissingChecksumsResponse { missing: HashSet, diff --git a/src/commands/upload_proguard.rs b/src/commands/upload_proguard.rs index cdb2cb69c2..fd1af97484 100644 --- a/src/commands/upload_proguard.rs +++ b/src/commands/upload_proguard.rs @@ -9,7 +9,6 @@ use symbolic::common::ByteView; use uuid::Uuid; use crate::api::Api; -use crate::api::AssociateProguard; use crate::config::Config; use crate::utils::android::dump_proguard_uuids_as_properties; use crate::utils::args::ArgExt as _; @@ -33,62 +32,11 @@ pub fn make_command(command: Command) -> Command { .num_args(1..) .action(ArgAction::Append), ) - .arg( - Arg::new("version") - .hide(true) - .long("version") - .value_name("VERSION") - .requires("app_id") - .help( - "[DEPRECATED] Optionally associate the mapping files \ - with a human readable version.{n}This helps you \ - understand which ProGuard files go with which version \ - of your app.\n\ - Sentry SaaS and self-hosted version 25.9.0 and later no \ - longer display this association, as it has no effect on \ - deobfuscation. This flag is scheduled for removal in \ - Sentry CLI 3.0.0.", - ), - ) - .arg( - Arg::new("version_code") - .hide(true) - .long("version-code") - .value_name("VERSION_CODE") - .requires("app_id") - .requires("version") - .help( - "[DEPRECATED] Optionally associate the mapping files with a version \ - code.{n}This helps you understand which ProGuard files \ - go with which version of your app.\n\ - Sentry SaaS and self-hosted version 25.9.0 and later no \ - longer display this association, as it has no effect on \ - deobfuscation. This flag is scheduled for removal in \ - Sentry CLI 3.0.0.", - ), - ) - .arg( - Arg::new("app_id") - .hide(true) - .long("app-id") - .value_name("APP_ID") - .requires("version") - .help( - "[DEPRECATED] Optionally associate the mapping files with an application \ - ID.{n}If you have multiple apps in one sentry project, you can \ - then easily tell them apart.\n\ - Sentry SaaS and self-hosted version 25.9.0 and later no \ - longer display this association, as it has no effect on \ - deobfuscation. This flag is scheduled for removal in \ - Sentry CLI 3.0.0.", - ), - ) .arg( Arg::new("platform") .hide(true) .long("platform") .value_name("PLATFORM") - .requires("app_id") .help( "[DEPRECATED] This flag is a no-op, scheduled \ for removal in Sentry CLI 3.0.0.", @@ -109,7 +57,6 @@ pub fn make_command(command: Command) -> Command { Arg::new("android_manifest") .long("android-manifest") .value_name("PATH") - .conflicts_with("app_id") .hide(true) .help( "[DEPRECATED] This flag is a no-op, scheduled \ @@ -304,40 +251,5 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { } } - // if values are given associate - if let Some(app_id) = matches.get_one::("app_id") { - log::warn!( - "[DEPRECATION NOTICE] The --app-id, --version, and --version-code flags are deprecated. \ - and scheduled for removal in Sentry CLI 3.0.0. \ - These values have no effect on deobfuscation, and are no longer displayed anywhere \ - in the Sentry UI (neither in SaaS nor in self-hosted versions 25.9.0 and later)." - ); - - #[expect(clippy::unwrap_used, reason = "legacy code")] - let version = matches.get_one::("version").unwrap().to_owned(); - let build: Option = matches.get_one::("version_code").cloned(); - - let mut release_name = app_id.to_owned(); - release_name.push('@'); - release_name.push_str(&version); - - if let Some(build_str) = build { - release_name.push('+'); - release_name.push_str(&build_str); - } - - for mapping in &mappings { - let uuid = forced_uuid.copied().unwrap_or(mapping.uuid()); - authenticated_api.associate_proguard_mappings( - &org, - &project, - &AssociateProguard { - release_name: release_name.clone(), - proguard_uuid: uuid.to_string(), - }, - )?; - } - } - Ok(()) } diff --git a/src/utils/proguard/upload.rs b/src/utils/proguard/upload.rs index f232eb83b2..ab9fbcc8b5 100644 --- a/src/utils/proguard/upload.rs +++ b/src/utils/proguard/upload.rs @@ -4,19 +4,12 @@ //! Proguard mappings, while we work on a more permanent solution, which will //! work for all different types of debug files. -use std::time::Duration; - use anyhow::Result; use crate::api::ChunkServerOptions; use crate::utils::chunks::{upload_chunked_objects, ChunkOptions, Chunked}; use crate::utils::proguard::ProguardMapping; -/// How long to wait for the server to assemble the mappings before giving up. -// 120 seconds was chosen somewhat arbitrarily, but in my testing, assembly -// usually was almost instantaneous, so this should probably be enough time. -const ASSEMBLE_POLL_TIMEOUT: Duration = Duration::from_secs(120); - /// Uploads a set of Proguard mappings to Sentry. /// Blocks until the mappings have been assembled (up to ASSEMBLE_POLL_TIMEOUT). /// Returns an error if the mappings fail to assemble, or if the timeout is reached. @@ -32,8 +25,7 @@ pub fn chunk_upload( .map(|mapping| Chunked::from(mapping, chunk_size)) .collect::>(); - let options = - ChunkOptions::new(chunk_upload_options, org, project).with_max_wait(ASSEMBLE_POLL_TIMEOUT); + let options = ChunkOptions::new(chunk_upload_options, org, project); let (_, has_processing_errors) = upload_chunked_objects(&chunked_mappings, options)?; diff --git a/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd b/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd index 5d2a42cc6d..194f9e5605 100644 --- a/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd +++ b/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd @@ -14,15 +14,15 @@ Options: in key:value format. -p, --project The project ID or slug. --auth-token Use the given Sentry auth token. + --no-upload Disable the actual upload. + This runs all steps for the processing but does not trigger the + upload. This is useful if you just want to verify the mapping + files and write the proguard UUIDs into a properties file. --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] - --no-upload Disable the actual upload. - This runs all steps for the processing but does not trigger the - upload. This is useful if you just want to verify the mapping - files and write the proguard UUIDs into a properties file. --write-properties Write the UUIDs for the processed mapping files into the given properties file. --require-one Requires at least one file to upload or the command will error. diff --git a/tests/integration/upload_proguard.rs b/tests/integration/upload_proguard.rs index 51e471e01d..97d9f0f2fb 100644 --- a/tests/integration/upload_proguard.rs +++ b/tests/integration/upload_proguard.rs @@ -152,38 +152,14 @@ fn chunk_upload_needs_upload() { }\ }" } - 2 => { - // Third call: Assembly completed - "{\ - \"297ecd9143fc2882e4b6758c1ccd13ea82930eeb\":{\ - \"state\":\"ok\",\ - \"detail\":null,\ - \"missingChunks\":[],\ - \"dif\":{\ - \"id\":\"12\",\ - \"uuid\":\"c038584d-c366-570c-ad1e-034fa0d194d7\",\ - \"debugId\":\"c038584d-c366-570c-ad1e-034fa0d194d7\",\ - \"codeId\":null,\ - \"cpuName\":\"any\",\ - \"objectName\":\"proguard-mapping\",\ - \"symbolType\":\"proguard\",\ - \"headers\":{\"Content-Type\":\"text/x-proguard+plain\"},\ - \"size\":155,\ - \"sha1\":\"297ecd9143fc2882e4b6758c1ccd13ea82930eeb\",\ - \"dateCreated\":\"1776-07-04T12:00:00.000Z\",\ - \"data\":{\"features\":[\"mapping\"]}\ - }\ - }\ - }" - } n => panic!( - "Only 3 calls to the assemble endpoint expected, but there were {}.", + "Only 2 calls to the assemble endpoint expected, but there were {}.", n + 1 ), } .into() }) - .expect(3), + .expect(2), ) .assert_cmd([ "upload-proguard", @@ -298,57 +274,14 @@ fn chunk_upload_two_files() { }\ }" } - 2 => { - // Third call: Assembly completed - "{\ - \"297ecd9143fc2882e4b6758c1ccd13ea82930eeb\":{\ - \"state\":\"ok\",\ - \"detail\":null,\ - \"missingChunks\":[],\ - \"dif\":{\ - \"id\":\"12\",\ - \"uuid\":\"c038584d-c366-570c-ad1e-034fa0d194d7\",\ - \"debugId\":\"c038584d-c366-570c-ad1e-034fa0d194d7\",\ - \"codeId\":null,\ - \"cpuName\":\"any\",\ - \"objectName\":\"proguard-mapping\",\ - \"symbolType\":\"proguard\",\ - \"headers\":{\"Content-Type\":\"text/x-proguard+plain\"},\ - \"size\":155,\ - \"sha1\":\"297ecd9143fc2882e4b6758c1ccd13ea82930eeb\",\ - \"dateCreated\":\"1776-07-04T12:00:00.000Z\",\ - \"data\":{\"features\":[\"mapping\"]}\ - }\ - },\ - \"e5329624a8d06e084941f133c75b5874f793ee7c\":{\ - \"state\":\"ok\",\ - \"detail\":null,\ - \"missingChunks\":[],\ - \"dif\":{\ - \"id\":\"13\",\ - \"uuid\":\"747e1d76-509b-5225-8a5b-db7b7d4067d4\",\ - \"debugId\":\"747e1d76-509b-5225-8a5b-db7b7d4067d4\",\ - \"codeId\":null,\ - \"cpuName\":\"any\",\ - \"objectName\":\"proguard-mapping\",\ - \"symbolType\":\"proguard\",\ - \"headers\":{\"Content-Type\":\"text/x-proguard+plain\"},\ - \"size\":158,\ - \"sha1\":\"e5329624a8d06e084941f133c75b5874f793ee7c\",\ - \"dateCreated\":\"1776-07-04T12:00:00.000Z\",\ - \"data\":{\"features\":[\"mapping\"]}\ - }\ - }\ - }" - } n => panic!( - "Only 3 calls to the assemble endpoint expected, but there were {}.", + "Only 2 calls to the assemble endpoint expected, but there were {}.", n + 1 ), } .into() }) - .expect(3), + .expect(2), ) .assert_cmd([ "upload-proguard", From b71947ca26d0ed38e04eb6ec3562d2c2c1906117 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 10 Nov 2025 12:20:00 +0100 Subject: [PATCH 08/19] fix(chunk): Fail with org not found on 404 to chunk endpoint (#2930) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ **Breaking change:** Do not merge until ready to release in a major. As Sentry CLI 3.0.0 will only support Sentry servers with chunk uploading support, we can now assume that 404 errors from the `/organizations/{org}/chunk-upload/` endpoint are due to the organization not existing, and not due to the chunk upload endpoint not existing. - Resolves #2900 - Resolves [CLI-211](https://linear.app/getsentry/issue/CLI-211/assume-404-when-getting-chunk-upload-endpoint-is-due-to-non-existent) ________ BREAKING CHANGE: Several subcommands no longer support Sentry servers which lack support for chunked uploads. --- CHANGELOG.md | 4 ++ src/api/errors/api_error.rs | 5 +- src/api/mod.rs | 17 ++----- src/commands/build/upload.rs | 7 +-- src/commands/dart_symbol_map/upload.rs | 5 +- src/commands/files/upload.rs | 2 +- src/commands/react_native/appcenter.rs | 4 +- src/commands/react_native/gradle.rs | 4 +- src/commands/react_native/xcode.rs | 6 +-- src/commands/sourcemaps/upload.rs | 10 ++-- src/commands/upload_proguard.rs | 12 +---- src/utils/dif_upload/mod.rs | 35 +++++++------- src/utils/file_upload.rs | 65 +++++++++++--------------- 13 files changed, 70 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e21dcd7b6..5c5a70db66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ - Removed the `upload-proguard` subcommand's `--app-id`, `--version`, and `--version-code` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. +### Fixes + +- Fixed misleading error message claiming the server doesn't support chunk uploading when the actual error was a non-existent organization ([#2930](https://github.com/getsentry/sentry-cli/pull/2930)). + ## 2.58.4 ### Fixes diff --git a/src/api/errors/api_error.rs b/src/api/errors/api_error.rs index 775f46d509..be6dda24fe 100644 --- a/src/api/errors/api_error.rs +++ b/src/api/errors/api_error.rs @@ -28,8 +28,6 @@ pub(in crate::api) enum ApiErrorKind { ProjectNotFound, #[error("Release not found. Ensure that you configured the correct release, project, and organization.")] ReleaseNotFound, - #[error("chunk upload endpoint not supported by sentry server")] - ChunkUploadNotSupported, #[error("API request failed")] RequestFailed, #[error("could not compress data")] @@ -63,6 +61,9 @@ impl ApiError { } } + // This method is currently only used in the macOS binary, there is no reason + // why not to expose it on other platforms, if we ever need it. + #[cfg(target_os = "macos")] pub(in crate::api) fn kind(&self) -> ApiErrorKind { self.inner } diff --git a/src/api/mod.rs b/src/api/mod.rs index 2778a2a364..f41459f406 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -956,21 +956,10 @@ impl<'a> AuthenticatedApi<'a> { } /// Get the server configuration for chunked file uploads. - pub fn get_chunk_upload_options(&self, org: &str) -> ApiResult> { + pub fn get_chunk_upload_options(&self, org: &str) -> ApiResult { let url = format!("/organizations/{}/chunk-upload/", PathArg(org)); - match self - .get(&url)? - .convert_rnf::(ApiErrorKind::ChunkUploadNotSupported) - { - Ok(options) => Ok(Some(options)), - Err(error) => { - if error.kind() == ApiErrorKind::ChunkUploadNotSupported { - Ok(None) - } else { - Err(error) - } - } - } + self.get(&url)? + .convert_rnf::(ApiErrorKind::OrganizationNotFound) } /// Request DIF assembling and processing from chunks. diff --git a/src/commands/build/upload.rs b/src/commands/build/upload.rs index ac2c770cb9..d272ede3ba 100644 --- a/src/commands/build/upload.rs +++ b/src/commands/build/upload.rs @@ -557,12 +557,7 @@ fn upload_file( build_configuration.unwrap_or("unknown"), ); - let chunk_upload_options = api.get_chunk_upload_options(org)?.ok_or_else(|| { - anyhow!( - "The Sentry server lacks chunked uploading support, which \ - is required for build uploads. {SELF_HOSTED_ERROR_HINT}" - ) - })?; + let chunk_upload_options = api.get_chunk_upload_options(org)?; if !chunk_upload_options.supports(ChunkUploadCapability::PreprodArtifacts) { bail!( diff --git a/src/commands/dart_symbol_map/upload.rs b/src/commands/dart_symbol_map/upload.rs index 297a8db65e..2784060806 100644 --- a/src/commands/dart_symbol_map/upload.rs +++ b/src/commands/dart_symbol_map/upload.rs @@ -132,10 +132,7 @@ pub(super) fn execute(args: DartSymbolMapUploadArgs) -> Result<()> { ))?; let chunk_upload_options = api .authenticated()? - .get_chunk_upload_options(org)? - .ok_or_else(|| anyhow::anyhow!( - "server does not support chunked uploading. Please update your Sentry server." - ))?; + .get_chunk_upload_options(org)?; if !chunk_upload_options.supports(ChunkUploadCapability::DartSymbolMap) { bail!( diff --git a/src/commands/files/upload.rs b/src/commands/files/upload.rs index 469211e4f4..160de7e1ac 100644 --- a/src/commands/files/upload.rs +++ b/src/commands/files/upload.rs @@ -159,7 +159,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, }; let path = Path::new(matches.get_one::("path").unwrap()); diff --git a/src/commands/react_native/appcenter.rs b/src/commands/react_native/appcenter.rs index 8205fec043..3d2d61564b 100644 --- a/src/commands/react_native/appcenter.rs +++ b/src/commands/react_native/appcenter.rs @@ -202,7 +202,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } Some(dists) => { @@ -220,7 +220,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } } diff --git a/src/commands/react_native/gradle.rs b/src/commands/react_native/gradle.rs index f8573c6ab4..e5a661f51a 100644 --- a/src/commands/react_native/gradle.rs +++ b/src/commands/react_native/gradle.rs @@ -129,7 +129,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } } else { @@ -142,7 +142,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } diff --git a/src/commands/react_native/xcode.rs b/src/commands/react_native/xcode.rs index a88f23486a..69b9822b1e 100644 --- a/src/commands/react_native/xcode.rs +++ b/src/commands/react_native/xcode.rs @@ -351,7 +351,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } else { let (dist, release_name) = match (&dist_from_env, &release_from_env) { @@ -386,7 +386,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } Some(dists) => { @@ -399,7 +399,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: None, wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, })?; } } diff --git a/src/commands/sourcemaps/upload.rs b/src/commands/sourcemaps/upload.rs index ecc98fa30c..b57b4f0c33 100644 --- a/src/commands/sourcemaps/upload.rs +++ b/src/commands/sourcemaps/upload.rs @@ -437,10 +437,10 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { log::warn!("The --use-artifact-bundle option and the SENTRY_FORCE_ARTIFACT_BUNDLES environment variable \ are both deprecated, and both will be removed in the next major version."); - if let Some(ref mut options) = chunk_upload_options { - if !options.supports(ChunkUploadCapability::ArtifactBundles) { - options.accept.push(ChunkUploadCapability::ArtifactBundles); - } + if !chunk_upload_options.supports(ChunkUploadCapability::ArtifactBundles) { + chunk_upload_options + .accept + .push(ChunkUploadCapability::ArtifactBundles); } } @@ -461,7 +461,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { note: matches.get_one::("note").map(String::as_str), wait, max_wait, - chunk_upload_options: chunk_upload_options.as_ref(), + chunk_upload_options: &chunk_upload_options, }; if matches.get_flag("strict") { diff --git a/src/commands/upload_proguard.rs b/src/commands/upload_proguard.rs index fd1af97484..2fa6ba4470 100644 --- a/src/commands/upload_proguard.rs +++ b/src/commands/upload_proguard.rs @@ -184,17 +184,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { authenticated_api = api.authenticated()?; (org, project) = config.get_org_and_project(matches)?; - let chunk_upload_options = authenticated_api - .get_chunk_upload_options(&org) - .map_err(|e| anyhow::anyhow!(e)) - .and_then(|options| { - options.ok_or_else(|| { - anyhow::anyhow!( - "server does not support chunked uploading. unset \ - {CHUNK_UPLOAD_ENV_VAR} to continue." - ) - }) - })?; + let chunk_upload_options = authenticated_api.get_chunk_upload_options(&org)?; proguard::chunk_upload(&mappings, chunk_upload_options, &org, &project)?; } else { diff --git a/src/utils/dif_upload/mod.rs b/src/utils/dif_upload/mod.rs index e576d3e343..bb4ccf3a32 100644 --- a/src/utils/dif_upload/mod.rs +++ b/src/utils/dif_upload/mod.rs @@ -1625,26 +1625,25 @@ impl<'a> DifUpload<'a> { } let api = Api::current(); - if let Some(chunk_options) = api.authenticated()?.get_chunk_upload_options(self.org)? { - if chunk_options.max_file_size > 0 { - self.max_file_size = chunk_options.max_file_size; - } - if chunk_options.max_wait > 0 { - self.max_wait = self - .max_wait - .min(Duration::from_secs(chunk_options.max_wait)); - } + let chunk_options = api.authenticated()?.get_chunk_upload_options(self.org)?; + if chunk_options.max_file_size > 0 { + self.max_file_size = chunk_options.max_file_size; + } + if chunk_options.max_wait > 0 { + self.max_wait = self + .max_wait + .min(Duration::from_secs(chunk_options.max_wait)); + } - self.pdbs_allowed = chunk_options.supports(ChunkUploadCapability::Pdbs); - self.portablepdbs_allowed = chunk_options.supports(ChunkUploadCapability::PortablePdbs); - self.sources_allowed = chunk_options.supports(ChunkUploadCapability::Sources); - self.bcsymbolmaps_allowed = chunk_options.supports(ChunkUploadCapability::BcSymbolmap); - self.il2cpp_mappings_allowed = chunk_options.supports(ChunkUploadCapability::Il2Cpp); + self.pdbs_allowed = chunk_options.supports(ChunkUploadCapability::Pdbs); + self.portablepdbs_allowed = chunk_options.supports(ChunkUploadCapability::PortablePdbs); + self.sources_allowed = chunk_options.supports(ChunkUploadCapability::Sources); + self.bcsymbolmaps_allowed = chunk_options.supports(ChunkUploadCapability::BcSymbolmap); + self.il2cpp_mappings_allowed = chunk_options.supports(ChunkUploadCapability::Il2Cpp); - if chunk_options.supports(ChunkUploadCapability::DebugFiles) { - self.validate_capabilities(); - return upload_difs_chunked(self, chunk_options); - } + if chunk_options.supports(ChunkUploadCapability::DebugFiles) { + self.validate_capabilities(); + return upload_difs_chunked(self, chunk_options); } self.validate_capabilities(); diff --git a/src/utils/file_upload.rs b/src/utils/file_upload.rs index cb837beb3e..95f03e90af 100644 --- a/src/utils/file_upload.rs +++ b/src/utils/file_upload.rs @@ -29,9 +29,6 @@ use crate::utils::source_bundle; use super::file_search::ReleaseFileMatch; -/// Fallback concurrency for release file uploads. -static DEFAULT_CONCURRENCY: usize = 4; - /// Old versions of Sentry cannot assemble artifact bundles straight away, they require /// that those bundles are associated to a release. /// @@ -42,11 +39,10 @@ pub fn initialize_legacy_release_upload(context: &UploadContext) -> Result<()> { // need to do anything here. Artifact bundles will also only work // if a project is provided which is technically unnecessary for the // legacy upload though it will unlikely to be what users want. + let chunk_options = context.chunk_upload_options; if context.projects.is_some() - && context.chunk_upload_options.is_some_and(|x| { - x.supports(ChunkUploadCapability::ArtifactBundles) - || x.supports(ChunkUploadCapability::ArtifactBundlesV2) - }) + && (chunk_options.supports(ChunkUploadCapability::ArtifactBundles) + || chunk_options.supports(ChunkUploadCapability::ArtifactBundlesV2)) { return Ok(()); } @@ -75,19 +71,8 @@ pub fn initialize_legacy_release_upload(context: &UploadContext) -> Result<()> { ..Default::default() }, )?; - } else if context.chunk_upload_options.is_some() { - bail!("This version of Sentry does not support artifact bundles. A release slug is required (provide with --release or by setting the SENTRY_RELEASE environment variable)"); } else { - // We got a 404 when trying to get the chunk options from the server. Most likely, the - // organization does not exist, though old self-hosted Sentry servers may also completely - // lack support for chunked uploads. - bail!( - "The provided organization \"{}\" does not exist. If you are using a self-hosted \ - Sentry server, it is also possible that your Sentry server lacks support for \ - uploading artifact bundles, in which case you need to provide a release slug with \ - --release or by setting the SENTRY_RELEASE environment variable.", - context.org - ); + bail!("This version of Sentry does not support artifact bundles. A release slug is required (provide with --release or by setting the SENTRY_RELEASE environment variable)"); } Ok(()) } @@ -101,7 +86,7 @@ pub struct UploadContext<'a> { pub note: Option<&'a str>, pub wait: bool, pub max_wait: Duration, - pub chunk_upload_options: Option<&'a ChunkServerOptions>, + pub chunk_upload_options: &'a ChunkServerOptions, } impl UploadContext<'_> { @@ -372,11 +357,17 @@ impl<'a> FileUpload<'a> { // multiple projects OK initialize_legacy_release_upload(self.context)?; - if let Some(chunk_options) = self.context.chunk_upload_options { - if chunk_options.supports(ChunkUploadCapability::ReleaseFiles) { - // multiple projects OK - return upload_files_chunked(self.context, &self.files, chunk_options); - } + if self + .context + .chunk_upload_options + .supports(ChunkUploadCapability::ReleaseFiles) + { + // multiple projects OK + return upload_files_chunked( + self.context, + &self.files, + self.context.chunk_upload_options, + ); } log::warn!( @@ -398,10 +389,7 @@ impl<'a> FileUpload<'a> { ); } - let concurrency = self - .context - .chunk_upload_options - .map_or(DEFAULT_CONCURRENCY, |o| usize::from(o.concurrency)); + let concurrency = self.context.chunk_upload_options.concurrency as usize; let legacy_context = &self.context.try_into().map_err(|e| { anyhow::anyhow!( @@ -701,15 +689,16 @@ fn print_upload_context_details(context: &UploadContext) { style("> Dist:").dim(), style(context.dist.unwrap_or("None")).yellow() ); - let upload_type = match context.chunk_upload_options { - None => "single file", - Some(opts) - if opts.supports(ChunkUploadCapability::ArtifactBundles) - || opts.supports(ChunkUploadCapability::ArtifactBundlesV2) => - { - "artifact bundle" - } - _ => "release bundle", + let upload_type = if context + .chunk_upload_options + .supports(ChunkUploadCapability::ArtifactBundles) + || context + .chunk_upload_options + .supports(ChunkUploadCapability::ArtifactBundlesV2) + { + "artifact bundle" + } else { + "release bundle" }; println!( "{} {}", From 1b17fc36334e5e1b812ad15aec4fd37175f2f901 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 10 Nov 2025 12:37:38 +0100 Subject: [PATCH 09/19] feat(proguard): Upload ProGuard with chunked uploading (#2918) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description ⚠️ **Breaking change:** Do not merge until ready to release in a major. Use chunked uploading for `sentry-cli upload-proguard`, as chunked uploads are generally more reliable than non-chunked uploads, and chunked uploading is the uploading method used by all other file uploading commands in Sentry CLI. Users who previously had set the `SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD` environment variable to opt into the chunk uploading behavior no longer need to set this variable, as all ProGuard files are always uploaded with chunked uploading. ### Issues - Resolves #2328 - Resolves [CLI-13](https://linear.app/getsentry/issue/CLI-13/make-chunk-uploads-the-default-for-proguard-files) _______ BREAKING CHANGE: The `sentry-cli upload-proguard` file can no longer upload to Sentry servers which lack support for receiving ProGuard mappings via chunked upload. --- CHANGELOG.md | 4 + src/commands/upload_proguard.rs | 96 +++++-------------- src/utils/proguard/mapping.rs | 5 - .../upload_proguard-no-upload.trycmd | 1 - .../upload_proguard/upload_proguard.trycmd | 9 -- .../debug_files/get-chunk-upload.json | 2 +- tests/integration/test_utils/test_manager.rs | 6 -- tests/integration/upload_proguard.rs | 11 +-- 8 files changed, 28 insertions(+), 106 deletions(-) delete mode 100644 tests/integration/_cases/upload_proguard/upload_proguard.trycmd diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c5a70db66..902523fc15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ - Removed the `upload-proguard` subcommand's `--app-id`, `--version`, and `--version-code` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. +### Improvements + +- The `sentry-cli upload-proguard` command now uses chunked uploading by default ([#2918](https://github.com/getsentry/sentry-cli/pull/2918)). Users who previously set the `SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD` environment variable to opt into this behavior no longer need to set the variable. + ### Fixes - Fixed misleading error message claiming the server doesn't support chunk uploading when the actual error was a non-existent organization ([#2930](https://github.com/getsentry/sentry-cli/pull/2930)). diff --git a/src/commands/upload_proguard.rs b/src/commands/upload_proguard.rs index 2fa6ba4470..e7dbb71d0b 100644 --- a/src/commands/upload_proguard.rs +++ b/src/commands/upload_proguard.rs @@ -1,4 +1,3 @@ -use std::env; use std::io; use anyhow::{bail, Error, Result}; @@ -9,16 +8,13 @@ use symbolic::common::ByteView; use uuid::Uuid; use crate::api::Api; +use crate::api::ChunkUploadCapability; use crate::config::Config; use crate::utils::android::dump_proguard_uuids_as_properties; use crate::utils::args::ArgExt as _; -use crate::utils::fs::TempFile; use crate::utils::proguard; use crate::utils::proguard::ProguardMapping; use crate::utils::system::QuietExit; -use crate::utils::ui::{copy_with_progress, make_byte_progress_bar}; - -const CHUNK_UPLOAD_ENV_VAR: &str = "SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD"; pub fn make_command(command: Command) -> Command { command @@ -167,79 +163,31 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { let api = Api::current(); let config = Config::current(); - // Don't initialize these until we confirm the user did not pass the --no-upload flag, - // or if we are using chunked uploading. This is because auth token, org, and project - // are not needed for the no-upload case. - let authenticated_api; - let (org, project); - - if env::var(CHUNK_UPLOAD_ENV_VAR) == Ok("1".into()) { - log::warn!( - "EXPERIMENTAL FEATURE: Uploading proguard mappings using chunked uploading. \ - Some functionality may be unavailable when using chunked uploading. Please unset \ - the {CHUNK_UPLOAD_ENV_VAR} variable if you encounter any \ - problems." - ); - - authenticated_api = api.authenticated()?; - (org, project) = config.get_org_and_project(matches)?; - - let chunk_upload_options = authenticated_api.get_chunk_upload_options(&org)?; - - proguard::chunk_upload(&mappings, chunk_upload_options, &org, &project)?; - } else { - if mappings.is_empty() && matches.get_flag("require_one") { - println!(); - eprintln!("{}", style("error: found no mapping files to upload").red()); - return Err(QuietExit(1).into()); - } - - println!("{} compressing mappings", style(">").dim()); - let tf = TempFile::create()?; - { - let mut zip = zip::ZipWriter::new(tf.open()?); - for mapping in &mappings { - let pb = make_byte_progress_bar(mapping.len() as u64); - zip.start_file( - format!("proguard/{}.txt", mapping.uuid()), - zip::write::SimpleFileOptions::default(), - )?; - copy_with_progress(&pb, &mut mapping.as_ref(), &mut zip)?; - pb.finish_and_clear(); - } - } + if mappings.is_empty() && matches.get_flag("require_one") { + println!(); + eprintln!("{}", style("error: found no mapping files to upload").red()); + return Err(QuietExit(1).into()); + } - // write UUIDs into the mapping file. - if let Some(p) = matches.get_one::("write_properties") { - let uuids: Vec<_> = mappings.iter().map(|x| x.uuid()).collect(); - dump_proguard_uuids_as_properties(p, &uuids)?; - } + // write UUIDs into the mapping file. + if let Some(p) = matches.get_one::("write_properties") { + let uuids: Vec<_> = mappings.iter().map(|x| x.uuid()).collect(); + dump_proguard_uuids_as_properties(p, &uuids)?; + } - if matches.get_flag("no_upload") { - println!("{} skipping upload.", style(">").dim()); - return Ok(()); - } + if matches.get_flag("no_upload") { + println!("{} skipping upload.", style(">").dim()); + return Ok(()); + } - println!("{} uploading mappings", style(">").dim()); - (org, project) = config.get_org_and_project(matches)?; + let authenticated_api = api.authenticated()?; + let (org, project) = config.get_org_and_project(matches)?; - authenticated_api = api.authenticated()?; + let chunk_upload_options = authenticated_api.get_chunk_upload_options(&org)?; - let rv = authenticated_api - .region_specific(&org) - .upload_dif_archive(&project, tf.path())?; - println!( - "{} Uploaded a total of {} new mapping files", - style(">").dim(), - style(rv.len()).yellow() - ); - if !rv.is_empty() { - println!("Newly uploaded debug symbols:"); - for df in rv { - println!(" {}", style(&df.id()).dim()); - } - } + if chunk_upload_options.supports(ChunkUploadCapability::Proguard) { + proguard::chunk_upload(&mappings, chunk_upload_options, &org, &project) + } else { + Err(anyhow::anyhow!("Server does not support uploading ProGuard mappings via chunked upload. Please update your Sentry server.")) } - - Ok(()) } diff --git a/src/utils/proguard/mapping.rs b/src/utils/proguard/mapping.rs index bfd86dea4f..40117cad5e 100644 --- a/src/utils/proguard/mapping.rs +++ b/src/utils/proguard/mapping.rs @@ -19,11 +19,6 @@ pub struct ProguardMapping<'a> { } impl<'a> ProguardMapping<'a> { - /// Get the length of the mapping in bytes. - pub fn len(&self) -> usize { - self.bytes.len() - } - /// Get the UUID of the mapping. pub fn uuid(&self) -> Uuid { self.uuid diff --git a/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd b/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd index 62f5f693f0..cb30fac691 100644 --- a/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd +++ b/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd @@ -2,7 +2,6 @@ $ sentry-cli upload-proguard tests/integration/_fixtures/proguard.txt --no-upload ? success warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information -> compressing mappings > skipping upload. ``` diff --git a/tests/integration/_cases/upload_proguard/upload_proguard.trycmd b/tests/integration/_cases/upload_proguard/upload_proguard.trycmd deleted file mode 100644 index ac28898ceb..0000000000 --- a/tests/integration/_cases/upload_proguard/upload_proguard.trycmd +++ /dev/null @@ -1,9 +0,0 @@ -``` -$ sentry-cli upload-proguard tests/integration/_fixtures/proguard.txt -? success -warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information -> compressing mappings -> uploading mappings -> Uploaded a total of 0 new mapping files - -``` diff --git a/tests/integration/_responses/debug_files/get-chunk-upload.json b/tests/integration/_responses/debug_files/get-chunk-upload.json index 98a8aa5dac..0b56be5b03 100644 --- a/tests/integration/_responses/debug_files/get-chunk-upload.json +++ b/tests/integration/_responses/debug_files/get-chunk-upload.json @@ -7,5 +7,5 @@ "concurrency": 8, "hashAlgorithm": "sha1", "compression": ["gzip"], - "accept": ["debug_files", "release_files", "pdbs", "portablepdbs", "sources", "bcsymbolmaps"] + "accept": ["debug_files", "release_files", "pdbs", "portablepdbs", "sources", "bcsymbolmaps", "proguard"] } diff --git a/tests/integration/test_utils/test_manager.rs b/tests/integration/test_utils/test_manager.rs index 6aec668f0d..bbec5385d1 100644 --- a/tests/integration/test_utils/test_manager.rs +++ b/tests/integration/test_utils/test_manager.rs @@ -201,12 +201,6 @@ impl AssertCmdTestManager { self } - /// Set a custom environment variable for the test. - pub fn env(mut self, variable: impl AsRef, value: impl AsRef) -> Self { - self.command.env(variable, value); - self - } - /// Run the command and perform assertions. /// /// This function asserts both the mocks and the command result. diff --git a/tests/integration/upload_proguard.rs b/tests/integration/upload_proguard.rs index 97d9f0f2fb..d6c148bc80 100644 --- a/tests/integration/upload_proguard.rs +++ b/tests/integration/upload_proguard.rs @@ -8,13 +8,7 @@ use crate::integration::{MockEndpointBuilder, TestManager}; #[test] fn command_upload_proguard() { - TestManager::new() - .mock_endpoint( - MockEndpointBuilder::new("POST", "/api/0/projects/wat-org/wat-project/files/dsyms/") - .with_response_body("[]"), - ) - .register_trycmd_test("upload_proguard/*.trycmd") - .with_default_token(); + TestManager::new().register_trycmd_test("upload_proguard/*.trycmd"); } #[test] @@ -72,7 +66,6 @@ fn chunk_upload_already_there() { "tests/integration/_fixtures/upload_proguard/mapping.txt", ]) .with_default_token() - .env("SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD", "1") .run_and_assert(AssertCommand::Success) } @@ -166,7 +159,6 @@ fn chunk_upload_needs_upload() { "tests/integration/_fixtures/upload_proguard/mapping.txt", ]) .with_default_token() - .env("SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD", "1") .run_and_assert(AssertCommand::Success) } @@ -289,6 +281,5 @@ fn chunk_upload_two_files() { "tests/integration/_fixtures/upload_proguard/mapping-2.txt", ]) .with_default_token() - .env("SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD", "1") .run_and_assert(AssertCommand::Success) } From 715d1ec6f1dfbe47a88aeedef2c2766310795bbd Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 11 Nov 2025 11:13:39 +0100 Subject: [PATCH 10/19] chore(auth): Remove API key authentication (#2935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ **Breaking change:** Do not merge until ready to release in a major. Removed support for the legacy API key authentication method. Users must now use auth tokens instead. Specifically, users supplying an API key via any of the following options need to generate and use an auth token instead: - `--api-key` CLI flag - `SENTRY_API_KEY` environment variable - `api_key` configuration file field - `apiKey` option in the JavaScript API - Resolves #2873 - Resolves [CLI-199](https://linear.app/getsentry/issue/CLI-199/remove-api-key-authentication) _____ BREAKING CHANGE: API-key based authentication is no longer supported. The `--api-key` CLI flag and `apiKey` JS option have been removed; the `SENTRY_API_KEY` environment variable and `api_key` configuration file field are no longer read. --- CHANGELOG.md | 11 ++++++++ lib/helper.js | 3 -- lib/types.ts | 11 +------- src/api/mod.rs | 14 ---------- src/commands/info.rs | 4 --- src/commands/login.rs | 2 -- src/commands/mod.rs | 19 ------------- src/config.rs | 28 ++----------------- .../build/build-upload-help-macos.trycmd | 6 ++-- .../build/build-upload-help-not-macos.trycmd | 6 ++-- .../debug_files-upload-help.trycmd | 10 +++---- .../_cases/events/events-list-help.trycmd | 2 +- .../_cases/issues/issues-help.trycmd | 2 +- .../_cases/issues/issues-list-help.trycmd | 2 +- .../_cases/logs/logs-list-help.trycmd | 16 +++++------ .../_cases/monitors/monitors-run-help.trycmd | 10 +++---- .../_cases/send_event/send_event-help.trycmd | 12 ++++---- .../send_metric-distribution-help.trycmd | 6 ++-- .../send_metric/send_metric-gauge-help.trycmd | 8 +++--- .../send_metric-increment-help.trycmd | 10 +++---- .../send_metric/send_metric-set-help.trycmd | 8 +++--- .../_cases/upload_dif/upload_dif-help.trycmd | 10 +++---- .../upload_dsym/upload_dsym-help.trycmd | 10 +++---- .../upload_proguard-help.trycmd | 4 +-- 24 files changed, 75 insertions(+), 139 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902523fc15..ca932ebf1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,19 @@ ### Breaking Changes +- Removed support for the legacy API key authentication method ([#2935](https://github.com/getsentry/sentry-cli/pull/2935)). Sentry CLI now only supports authenticating with Auth Tokens. If you are using API key authentication via any of the following methods, you need to generate and use an [Auth Token](https://docs.sentry.io/account/auth-tokens/), instead: + - `--api-key` CLI flag + - `SENTRY_API_KEY` environment variable + - `api_key` configuration file field + - `apiKey` option in the JavaScript API - Removed the `upload-proguard` subcommand's `--app-id`, `--version`, and `--version-code` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. +#### Node.js Wrapper Breakages + +The following changes only apply when using `sentry-cli` via the npm package [`@sentry/cli`](https://www.npmjs.com/package/@sentry/cli): + +- Removed the `apiKey` option from `SentryCliOptions` ([#2935](https://github.com/getsentry/sentry-cli/pull/2935)). If you are using `apiKey`, you need to generate and use an [Auth Token](https://docs.sentry.io/account/auth-tokens/) via the `authToken` option, instead. + ### Improvements - The `sentry-cli upload-proguard` command now uses chunked uploading by default ([#2918](https://github.com/getsentry/sentry-cli/pull/2918)). Users who previously set the `SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD` environment variable to opt into this behavior no longer need to set the variable. diff --git a/lib/helper.js b/lib/helper.js index 19028a5ddb..f2784b9989 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -302,9 +302,6 @@ async function execute(args, live, silent, configFile, config = {}) { if (config.authToken) { env.SENTRY_AUTH_TOKEN = config.authToken; } - if (config.apiKey) { - env.SENTRY_API_KEY = config.apiKey; - } if (config.dsn) { env.SENTRY_DSN = config.dsn; } diff --git a/lib/types.ts b/lib/types.ts index 4e703921ea..26d92214fb 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -16,13 +16,6 @@ export interface SentryCliOptions { * This value will update `SENTRY_AUTH_TOKEN` env variable. */ authToken?: string; - /** - * API key to authenticate any HTTP requests to Sentry (legacy authentication method). - * This value will update `SENTRY_API_KEY` env variable. - * @deprecated Use auth-token-based authentication via `authToken` instead. - * This option is scheduled for removal in the next major release. - */ - apiKey?: string; /** * Sentry DSN. * This value will update `SENTRY_DSN` env variable. @@ -68,7 +61,6 @@ export type SourceMapsPathDescriptor = Omit; + new (release: string, options?: { projects: string[] } | string[]): Promise; setCommits(release: string, options: SentryCliCommitsOptions): Promise; @@ -241,4 +233,3 @@ export interface SentryCliReleases { execute(args: string[], live: boolean | 'rejectOnError'): Promise; } - diff --git a/src/api/mod.rs b/src/api/mod.rs index f41459f406..f69ac2d658 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1370,14 +1370,6 @@ impl<'a> AuthenticatedApi<'a> { region_url.ok().map(|url| url.into()) } }, - #[expect(deprecated, reason = "Auth key is deprecated.")] - Auth::Key(_) => { - log::warn!( - "Auth key is not supported for region-specific API. Falling back to default region." - ); - - None - } }; RegionSpecificApi { @@ -1731,12 +1723,6 @@ impl ApiRequest { pub fn with_auth(mut self, auth: &Auth) -> ApiResult { self.is_authenticated = true; match *auth { - #[expect(deprecated, reason = "API key is deprecated.")] - Auth::Key(ref key) => { - self.handle.username(key)?; - debug!("using deprecated key based authentication"); - Ok(self) - } Auth::Token(ref token) => { debug!("using token authentication"); self.with_header( diff --git a/src/commands/info.rs b/src/commands/info.rs index 8ba9f3ef56..7d37f06f67 100644 --- a/src/commands/info.rs +++ b/src/commands/info.rs @@ -59,8 +59,6 @@ fn describe_auth(auth: Option<&Auth>) -> &str { match auth { None => "Unauthorized", Some(&Auth::Token(_)) => "Auth Token", - #[expect(deprecated, reason = "API key is deprecated.")] - Some(&Auth::Key(_)) => "API Key (deprecated)", } } @@ -75,8 +73,6 @@ fn get_config_status_json() -> Result<()> { rv.auth.auth_type = config.get_auth().map(|val| match val { Auth::Token(_) => "token".into(), - #[expect(deprecated, reason = "API key is deprecated.")] - Auth::Key(_) => "api_key".into(), }); rv.auth.successful = config.get_auth().is_some() && Api::current().authenticated()?.get_auth_info().is_ok(); diff --git a/src/commands/login.rs b/src/commands/login.rs index 00754e56d1..eed0e7738f 100644 --- a/src/commands/login.rs +++ b/src/commands/login.rs @@ -140,8 +140,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { fn get_org_from_auth(auth: &Auth) -> Option<&str> { match auth { Auth::Token(token) => get_org_from_token(token), - #[expect(deprecated, reason = "API key is deprecated.")] - Auth::Key(_) => None, } } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 522c1581b6..6b829a915a 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -137,18 +137,6 @@ fn preexecute_hooks() -> Result { } fn configure_args(config: &mut Config, matches: &ArgMatches) { - if let Some(api_key) = matches.get_one::("api_key") { - log::warn!( - "[DEPRECTATION NOTICE] API key authentication and the --api-key argument are \ - deprecated. \ - Please generate an auth token, and use the --auth-token argument instead." - ); - - #[expect(deprecated, reason = "Auth key is deprecated.")] - let auth = Auth::Key(api_key.to_owned()); - config.set_auth(auth); - } - if let Some(auth_token) = matches.get_one::("auth_token") { config.set_auth(Auth::Token(auth_token.to_owned())); } @@ -192,13 +180,6 @@ fn app() -> Command { .value_parser(auth_token_parser) .help("Use the given Sentry auth token."), ) - .arg( - Arg::new("api_key") - .value_name("API_KEY") - .long("api-key") - .hide(true) - .help("[DEPRECATED] Use the given Sentry API key."), - ) .arg( Arg::new("log_level") .value_name("LOG_LEVEL") diff --git a/src/config.rs b/src/config.rs index 894c750403..18683f164d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,8 +36,6 @@ const MAX_RETRIES_INI_KEY: &str = "max_retries"; /// Represents the auth information #[derive(Debug, Clone)] pub enum Auth { - #[deprecated(note = "Auth Key authentication is deprecated.")] - Key(String), Token(AuthToken), } @@ -181,7 +179,6 @@ impl Config { pub fn set_auth(&mut self, auth: Auth) { self.cached_auth = Some(auth); - self.ini.delete_from(Some("auth"), "api_key"); self.ini.delete_from(Some("auth"), "token"); match self.cached_auth { Some(Auth::Token(ref val)) => { @@ -197,10 +194,6 @@ impl Config { val.raw().expose_secret().clone(), ); } - #[expect(deprecated, reason = "API key is deprecated.")] - Some(Auth::Key(ref val)) => { - self.ini.set_to(Some("auth"), "api_key".into(), val.clone()); - } None => {} } } @@ -739,26 +732,9 @@ impl Clone for Config { fn get_default_auth(ini: &Ini) -> Option { if let Ok(val) = env::var("SENTRY_AUTH_TOKEN") { Some(Auth::Token(val.into())) - } else if let Ok(val) = env::var("SENTRY_API_KEY") { - log::warn!( - "[DEPRECTATION NOTICE] API key authentication and the `SENTRY_API_KEY` environment \ - variable are deprecated. \ - Please generate and set an auth token using `SENTRY_AUTH_TOKEN` instead." - ); - #[expect(deprecated, reason = "API key is deprecated.")] - Some(Auth::Key(val)) - } else if let Some(val) = ini.get_from(Some("auth"), "token") { - Some(Auth::Token(val.into())) - } else if let Some(val) = ini.get_from(Some("auth"), "api_key") { - log::warn!( - "[DEPRECTATION NOTICE] API key authentication and the `api_key` field in the \ - Sentry CLI config file are deprecated. \ - Please generate and set an auth token instead." - ); - #[expect(deprecated, reason = "API key is deprecated.")] - Some(Auth::Key(val.to_owned())) } else { - None + ini.get_from(Some("auth"), "token") + .map(|val| Auth::Token(val.into())) } } diff --git a/tests/integration/_cases/build/build-upload-help-macos.trycmd b/tests/integration/_cases/build/build-upload-help-macos.trycmd index acde89c3f4..72b1d88a0c 100644 --- a/tests/integration/_cases/build/build-upload-help-macos.trycmd +++ b/tests/integration/_cases/build/build-upload-help-macos.trycmd @@ -26,15 +26,15 @@ Options: current and remote branch will be used. --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + --quiet + Do not print any output while preserving correct exit code. This flag is currently + implemented only for selected subcommands. [aliases: --silent] --vcs-provider The VCS provider to use for the upload. If not provided, the current provider will be used. --head-repo-name The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used. - --quiet - Do not print any output while preserving correct exit code. This flag is currently - implemented only for selected subcommands. [aliases: --silent] --base-repo-name The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used. diff --git a/tests/integration/_cases/build/build-upload-help-not-macos.trycmd b/tests/integration/_cases/build/build-upload-help-not-macos.trycmd index 3156bd8bfa..b144a302c6 100644 --- a/tests/integration/_cases/build/build-upload-help-not-macos.trycmd +++ b/tests/integration/_cases/build/build-upload-help-not-macos.trycmd @@ -25,15 +25,15 @@ Options: current and remote branch will be used. --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + --quiet + Do not print any output while preserving correct exit code. This flag is currently + implemented only for selected subcommands. [aliases: --silent] --vcs-provider The VCS provider to use for the upload. If not provided, the current provider will be used. --head-repo-name The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used. - --quiet - Do not print any output while preserving correct exit code. This flag is currently - implemented only for selected subcommands. [aliases: --silent] --base-repo-name The name of the git repository to use for the upload (e.g. organization/repository). If not provided, the current repository will be used. diff --git a/tests/integration/_cases/debug_files/not_windows/debug_files-upload-help.trycmd b/tests/integration/_cases/debug_files/not_windows/debug_files-upload-help.trycmd index cc2a86df0b..d663e891d8 100644 --- a/tests/integration/_cases/debug_files/not_windows/debug_files-upload-help.trycmd +++ b/tests/integration/_cases/debug_files/not_windows/debug_files-upload-help.trycmd @@ -17,22 +17,22 @@ Options: -t, --type Only consider debug information files of the given type. By default, all types are considered. [possible values: bcsymbolmap, breakpad, dsym, elf, jvm, pdb, pe, portablepdb, sourcebundle, wasm] + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] --no-unwind Do not scan for stack unwinding information. Specify this flag for builds with disabled FPO, or when stackwalking occurs on the device. This usually excludes executables and dynamic libraries. They might still be uploaded, if they contain additional processable information (see other flags). - --log-level Set the log output verbosity. [possible values: trace, debug, info, - warn, error] --no-debug Do not scan for debugging information. This will usually exclude debug companion files. They might still be uploaded, if they contain additional processable information (see other flags). - --no-sources Do not scan for source information. This will usually exclude - source bundle files. They might still be uploaded, if they contain - additional processable information (see other flags). --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] + --no-sources Do not scan for source information. This will usually exclude + source bundle files. They might still be uploaded, if they contain + additional processable information (see other flags). --id Search for specific debug identifiers. --require-all Errors if not all identifiers specified with --id could be found. --symbol-maps Optional path to BCSymbolMap files which are used to resolve hidden diff --git a/tests/integration/_cases/events/events-list-help.trycmd b/tests/integration/_cases/events/events-list-help.trycmd index 1191c4a692..6910bbb9d9 100644 --- a/tests/integration/_cases/events/events-list-help.trycmd +++ b/tests/integration/_cases/events/events-list-help.trycmd @@ -14,9 +14,9 @@ Options: -T, --show-tags Display the Tags column. --auth-token Use the given Sentry auth token. --max-rows Maximum number of rows to print. - --pages Maximum number of pages to fetch (100 events/page). [default: 5] --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + --pages Maximum number of pages to fetch (100 events/page). [default: 5] --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] diff --git a/tests/integration/_cases/issues/issues-help.trycmd b/tests/integration/_cases/issues/issues-help.trycmd index 4e152984d7..71bac53175 100644 --- a/tests/integration/_cases/issues/issues-help.trycmd +++ b/tests/integration/_cases/issues/issues-help.trycmd @@ -22,9 +22,9 @@ Options: -s, --status Select all issues matching a given status. [possible values: resolved, muted, unresolved] -a, --all Select all issues (this might be limited). - -i, --id Select the issue with the given ID. --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -i, --id Select the issue with the given ID. --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] diff --git a/tests/integration/_cases/issues/issues-list-help.trycmd b/tests/integration/_cases/issues/issues-list-help.trycmd index bdbee63705..6ef3a8ccae 100644 --- a/tests/integration/_cases/issues/issues-list-help.trycmd +++ b/tests/integration/_cases/issues/issues-list-help.trycmd @@ -19,9 +19,9 @@ Options: -s, --status Select all issues matching a given status. [possible values: resolved, muted, unresolved] -a, --all Select all issues (this might be limited). - -i, --id Select the issue with the given ID. --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -i, --id Select the issue with the given ID. --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] diff --git a/tests/integration/_cases/logs/logs-list-help.trycmd b/tests/integration/_cases/logs/logs-list-help.trycmd index 035ff5e018..93a2f3a5bc 100644 --- a/tests/integration/_cases/logs/logs-list-help.trycmd +++ b/tests/integration/_cases/logs/logs-list-help.trycmd @@ -28,6 +28,9 @@ Options: [default: 100] + --log-level + Set the log output verbosity. [possible values: trace, debug, info, warn, error] + --query Query to filter logs. Example: "level:error". If omitted, no filtering is applied. See https://docs.sentry.io/concepts/search/ for syntax. @@ -35,20 +38,17 @@ Options: --live Live stream logs. - --log-level - Set the log output verbosity. [possible values: trace, debug, info, warn, error] - - --poll-interval - Poll interval in seconds (must be > 0). Only used when --live is specified. - - [default: 2] - --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] + --poll-interval + Poll interval in seconds (must be > 0). Only used when --live is specified. + + [default: 2] + -h, --help Print help (see a summary with '-h') diff --git a/tests/integration/_cases/monitors/monitors-run-help.trycmd b/tests/integration/_cases/monitors/monitors-run-help.trycmd index c1253a5a28..ffd7884ee3 100644 --- a/tests/integration/_cases/monitors/monitors-run-help.trycmd +++ b/tests/integration/_cases/monitors/monitors-run-help.trycmd @@ -21,20 +21,20 @@ Options: --check-in-margin The allowed margin of minutes after the expected check-in time that the monitor will not be considered missed for. Requires --schedule. + --log-level + Set the log output verbosity. [possible values: trace, debug, info, warn, error] --max-runtime The allowed duration in minutes that the monitor may be in progress for before being considered failed due to timeout. Requires --schedule. - --log-level - Set the log output verbosity. [possible values: trace, debug, info, warn, error] + --quiet + Do not print any output while preserving correct exit code. This flag is currently + implemented only for selected subcommands. [aliases: --silent] --timezone A tz database string (e.g. "Europe/Vienna") representing the monitor's execution schedule's timezone. Requires --schedule. --failure-issue-threshold The number of consecutive missed or error check-ins that trigger an issue. Requires --schedule. - --quiet - Do not print any output while preserving correct exit code. This flag is currently - implemented only for selected subcommands. [aliases: --silent] --recovery-threshold The number of consecutive successful check-ins that resolve an issue. Requires --schedule. -h, --help diff --git a/tests/integration/_cases/send_event/send_event-help.trycmd b/tests/integration/_cases/send_event/send_event-help.trycmd index cfd1f134e7..95755972c0 100644 --- a/tests/integration/_cases/send_event/send_event-help.trycmd +++ b/tests/integration/_cases/send_event/send_event-help.trycmd @@ -31,24 +31,24 @@ Options: --timestamp Optional event timestamp in one of supported formats: unix timestamp, RFC2822 or RFC3339. + --log-level + Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -r, --release Optional identifier of the release. -d, --dist Set the distribution. - --log-level - Set the log output verbosity. [possible values: trace, debug, info, warn, error] - - -E, --env - Send with a specific environment. - --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] + -E, --env + Send with a specific environment. + --no-environ Do not send environment variables along diff --git a/tests/integration/_cases/send_metric/send_metric-distribution-help.trycmd b/tests/integration/_cases/send_metric/send_metric-distribution-help.trycmd index dfc3fd6e6b..3896ad04c3 100644 --- a/tests/integration/_cases/send_metric/send_metric-distribution-help.trycmd +++ b/tests/integration/_cases/send_metric/send_metric-distribution-help.trycmd @@ -27,12 +27,12 @@ Options: Metric tags as key:value pairs. Tags allow you to add dimensions to your metrics and can be filtered or grouped by in Sentry. - -v, --value - Metric value, any finite 64 bit float. - --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -v, --value + Metric value, any finite 64 bit float. + --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. diff --git a/tests/integration/_cases/send_metric/send_metric-gauge-help.trycmd b/tests/integration/_cases/send_metric/send_metric-gauge-help.trycmd index c27a3800a6..73f2faf480 100644 --- a/tests/integration/_cases/send_metric/send_metric-gauge-help.trycmd +++ b/tests/integration/_cases/send_metric/send_metric-gauge-help.trycmd @@ -27,16 +27,16 @@ Options: Metric tags as key:value pairs. Tags allow you to add dimensions to your metrics and can be filtered or grouped by in Sentry. - -v, --value - Metric value, any finite 64 bit float. - --log-level Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -v, --value + Metric value, any finite 64 bit float. + --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. -[..] + [aliases: --silent] -h, --help diff --git a/tests/integration/_cases/send_metric/send_metric-increment-help.trycmd b/tests/integration/_cases/send_metric/send_metric-increment-help.trycmd index 477cdf753b..adce7354d2 100644 --- a/tests/integration/_cases/send_metric/send_metric-increment-help.trycmd +++ b/tests/integration/_cases/send_metric/send_metric-increment-help.trycmd @@ -27,18 +27,18 @@ Options: Metric tags as key:value pairs. Tags allow you to add dimensions to your metrics and can be filtered or grouped by in Sentry. + --log-level + Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -v, --value Value to increment the metric by, any finite 64 bit float. -[..] + [default: 1] - --log-level - Set the log output verbosity. [possible values: trace, debug, info, warn, error] - --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. -[..] + [aliases: --silent] -h, --help diff --git a/tests/integration/_cases/send_metric/send_metric-set-help.trycmd b/tests/integration/_cases/send_metric/send_metric-set-help.trycmd index 84da4ecd25..74c0f0003b 100644 --- a/tests/integration/_cases/send_metric/send_metric-set-help.trycmd +++ b/tests/integration/_cases/send_metric/send_metric-set-help.trycmd @@ -27,17 +27,17 @@ Options: Metric tags as key:value pairs. Tags allow you to add dimensions to your metrics and can be filtered or grouped by in Sentry. + --log-level + Set the log output verbosity. [possible values: trace, debug, info, warn, error] + -v, --value Value to add to the set. If the set already contains the provided value, the set's unique count will not increase. - --log-level - Set the log output verbosity. [possible values: trace, debug, info, warn, error] - --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. -[..] + [aliases: --silent] -h, --help diff --git a/tests/integration/_cases/upload_dif/upload_dif-help.trycmd b/tests/integration/_cases/upload_dif/upload_dif-help.trycmd index 8fefa8120c..3c212473cf 100644 --- a/tests/integration/_cases/upload_dif/upload_dif-help.trycmd +++ b/tests/integration/_cases/upload_dif/upload_dif-help.trycmd @@ -17,22 +17,22 @@ Options: -t, --type Only consider debug information files of the given type. By default, all types are considered. [possible values: bcsymbolmap, breakpad, dsym, elf, jvm, pdb, pe, portablepdb, sourcebundle, wasm] + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] --no-unwind Do not scan for stack unwinding information. Specify this flag for builds with disabled FPO, or when stackwalking occurs on the device. This usually excludes executables and dynamic libraries. They might still be uploaded, if they contain additional processable information (see other flags). - --log-level Set the log output verbosity. [possible values: trace, debug, info, - warn, error] --no-debug Do not scan for debugging information. This will usually exclude debug companion files. They might still be uploaded, if they contain additional processable information (see other flags). - --no-sources Do not scan for source information. This will usually exclude - source bundle files. They might still be uploaded, if they contain - additional processable information (see other flags). --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] + --no-sources Do not scan for source information. This will usually exclude + source bundle files. They might still be uploaded, if they contain + additional processable information (see other flags). --id Search for specific debug identifiers. --require-all Errors if not all identifiers specified with --id could be found. --symbol-maps Optional path to BCSymbolMap files which are used to resolve hidden diff --git a/tests/integration/_cases/upload_dsym/upload_dsym-help.trycmd b/tests/integration/_cases/upload_dsym/upload_dsym-help.trycmd index d860eebf0f..b5d4a76c30 100644 --- a/tests/integration/_cases/upload_dsym/upload_dsym-help.trycmd +++ b/tests/integration/_cases/upload_dsym/upload_dsym-help.trycmd @@ -17,22 +17,22 @@ Options: -t, --type Only consider debug information files of the given type. By default, all types are considered. [possible values: bcsymbolmap, breakpad, dsym, elf, jvm, pdb, pe, portablepdb, sourcebundle, wasm] + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] --no-unwind Do not scan for stack unwinding information. Specify this flag for builds with disabled FPO, or when stackwalking occurs on the device. This usually excludes executables and dynamic libraries. They might still be uploaded, if they contain additional processable information (see other flags). - --log-level Set the log output verbosity. [possible values: trace, debug, info, - warn, error] --no-debug Do not scan for debugging information. This will usually exclude debug companion files. They might still be uploaded, if they contain additional processable information (see other flags). - --no-sources Do not scan for source information. This will usually exclude - source bundle files. They might still be uploaded, if they contain - additional processable information (see other flags). --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] + --no-sources Do not scan for source information. This will usually exclude + source bundle files. They might still be uploaded, if they contain + additional processable information (see other flags). --id Search for specific debug identifiers. --require-all Errors if not all identifiers specified with --id could be found. --symbol-maps Optional path to BCSymbolMap files which are used to resolve hidden diff --git a/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd b/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd index 194f9e5605..f764213a32 100644 --- a/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd +++ b/tests/integration/_cases/upload_proguard/upload_proguard-help.trycmd @@ -14,12 +14,12 @@ Options: in key:value format. -p, --project The project ID or slug. --auth-token Use the given Sentry auth token. + --log-level Set the log output verbosity. [possible values: trace, debug, info, + warn, error] --no-upload Disable the actual upload. This runs all steps for the processing but does not trigger the upload. This is useful if you just want to verify the mapping files and write the proguard UUIDs into a properties file. - --log-level Set the log output verbosity. [possible values: trace, debug, info, - warn, error] --quiet Do not print any output while preserving correct exit code. This flag is currently implemented only for selected subcommands. [aliases: --silent] From 21b4c7c6220f4ac77ae53f965e0171e426875d6e Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 11 Nov 2025 15:53:03 +0100 Subject: [PATCH 11/19] chore(proguard): Remove `--android-manifest` argument (#2940) ### Description This argument does not do anything, so we will remove it. ### Issues - Resolves #2874 - Resolves [CLI-200](https://linear.app/getsentry/issue/CLI-200/remove-upload-proguards-android-manifest-argument) --- CHANGELOG.md | 2 +- src/commands/upload_proguard.rs | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca932ebf1e..7e4f3ec184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - `SENTRY_API_KEY` environment variable - `api_key` configuration file field - `apiKey` option in the JavaScript API -- Removed the `upload-proguard` subcommand's `--app-id`, `--version`, and `--version-code` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. +- Removed the `upload-proguard` subcommand's `--app-id`, `--version`, `--version-code`, and `--android-manifest` arguments ([#2876](https://github.com/getsentry/sentry-cli/pull/2876), [#2940](https://github.com/getsentry/sentry-cli/pull/2940)). Users using these arguments should stop using them, as they are unnecessary. The information passed to these arguments is no longer visible in Sentry. #### Node.js Wrapper Breakages diff --git a/src/commands/upload_proguard.rs b/src/commands/upload_proguard.rs index e7dbb71d0b..36c72ca855 100644 --- a/src/commands/upload_proguard.rs +++ b/src/commands/upload_proguard.rs @@ -49,16 +49,6 @@ pub fn make_command(command: Command) -> Command { proguard UUIDs into a properties file.", ), ) - .arg( - Arg::new("android_manifest") - .long("android-manifest") - .value_name("PATH") - .hide(true) - .help( - "[DEPRECATED] This flag is a no-op, scheduled \ - for removal in Sentry CLI 3.0.0.", - ), - ) .arg( Arg::new("write_properties") .long("write-properties") @@ -100,14 +90,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { ); } - if matches.get_one::("android_manifest").is_some() { - log::warn!( - "[DEPRECATION NOTICE] The --android-manifest argument is deprecated, \ - and is scheduled for removal in Sentry CLI 3.0.0. \ - The argument is a no-op." - ); - } - let paths: Vec<_> = match matches.get_many::("paths") { Some(paths) => paths.collect(), None => { From 353bd0a7366e13314a0152420c7bd6d78000cf78 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 12 Nov 2025 13:02:44 +0100 Subject: [PATCH 12/19] chore(sourcemaps): Remove `sourcemaps explain` (#2947) ### Description Removed the `sentry-cli sourcemaps explain` command, which has been deprecated for some time. ### Issues - Resolves #2865 - Resolves [CLI-2865](https://linear.app/getsentry/issue/CLI-195/remove-sentry-cli-sourcemaps-explain-command) --- CHANGELOG.md | 1 + src/api/mod.rs | 109 +--- src/commands/sourcemaps/explain.rs | 521 ------------------ src/commands/sourcemaps/mod.rs | 2 - .../sourcemaps-explain-already-mapped.trycmd | 22 - ...maps-explain-artifact-dist-mismatch.trycmd | 14 - ...sourcemaps-explain-artifact-no-dist.trycmd | 14 - ...ps-explain-detect-from-file-content.trycmd | 17 - ...xplain-detect-from-sourcemap-header.trycmd | 16 - ...plain-detect-from-xsourcemap-header.trycmd | 16 - .../sourcemaps-explain-event-no-dist.trycmd | 14 - ...aps-explain-frame-malformed-abspath.trycmd | 11 - ...sourcemaps-explain-frame-no-abspath.trycmd | 11 - ...urcemaps-explain-frame-no-extension.trycmd | 11 - .../sourcemaps-explain-frame-no-inapp.trycmd | 11 - .../sourcemaps/sourcemaps-explain-help.trycmd | 29 - .../sourcemaps-explain-missing-event.trycmd | 8 - ...ourcemaps-explain-missing-exception.trycmd | 9 - .../sourcemaps-explain-missing-release.trycmd | 11 - ...urcemaps-explain-missing-stacktrace.trycmd | 10 - .../sourcemaps-explain-no-artifacts.trycmd | 12 - ...cemaps-explain-no-matching-artifact.trycmd | 11 - ...s-explain-partial-matching-artifact.trycmd | 12 - .../sourcemaps-explain-print-sourcemap.trycmd | 27 - ...s-explain-select-frame-out-of-range.trycmd | 11 - .../sourcemaps-explain-select-frame.trycmd | 11 - .../sourcemaps/sourcemaps-explain.trycmd | 11 - tests/integration/sourcemaps/explain.rs | 417 -------------- tests/integration/sourcemaps/mod.rs | 1 - 29 files changed, 5 insertions(+), 1365 deletions(-) delete mode 100644 src/commands/sourcemaps/explain.rs delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-already-mapped.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-artifact-dist-mismatch.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-artifact-no-dist.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-detect-from-file-content.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-detect-from-sourcemap-header.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-detect-from-xsourcemap-header.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-event-no-dist.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-frame-malformed-abspath.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-frame-no-abspath.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-frame-no-extension.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-frame-no-inapp.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-help.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-missing-event.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-missing-exception.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-missing-release.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-missing-stacktrace.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-no-artifacts.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-no-matching-artifact.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-partial-matching-artifact.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-print-sourcemap.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-select-frame-out-of-range.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain-select-frame.trycmd delete mode 100644 tests/integration/_cases/sourcemaps/sourcemaps-explain.trycmd delete mode 100644 tests/integration/sourcemaps/explain.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e4f3ec184..00703aedaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Breaking Changes +- Removed the `sentry-cli sourcemaps explain` command ([#2947](https://github.com/getsentry/sentry-cli/pull/2947)). The command had been deprecated for some time, since Sentry now has a better in-product debugging flow for source map problems via the "Unminify Code" button, which is displayed on any JavaScript issues which could not be unminified. - Removed support for the legacy API key authentication method ([#2935](https://github.com/getsentry/sentry-cli/pull/2935)). Sentry CLI now only supports authenticating with Auth Tokens. If you are using API key authentication via any of the following methods, you need to generate and use an [Auth Token](https://docs.sentry.io/account/auth-tokens/), instead: - `--api-key` CLI flag - `SENTRY_API_KEY` environment variable diff --git a/src/api/mod.rs b/src/api/mod.rs index f69ac2d658..a400e6981f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -37,7 +37,6 @@ use log::{debug, info, warn}; use parking_lot::Mutex; use regex::{Captures, Regex}; use secrecy::ExposeSecret as _; -use sentry::protocol::{Exception, Values}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sha1_smol::Digest; @@ -286,6 +285,10 @@ impl Api { } /// Convenience method that downloads a file into the given file object. + /// + /// Currently only used on macOS, but we could make it available on other platforms + /// if needed. + #[cfg(target_os = "macos")] pub fn download(&self, url: &str, dst: &mut File) -> ApiResult { self.request(Method::Get, url, None)? .follow_location(true)? @@ -551,73 +554,6 @@ impl<'a> AuthenticatedApi<'a> { self.list_release_files_by_checksum(org, project, release, &[]) } - /// Get a single release file and store it inside provided descriptor. - pub fn get_release_file( - &self, - org: &str, - project: Option<&str>, - version: &str, - file_id: &str, - file_desc: &mut File, - ) -> Result<(), ApiError> { - let path = if let Some(project) = project { - format!( - "/projects/{}/{}/releases/{}/files/{}/?download=1", - PathArg(org), - PathArg(project), - PathArg(version), - PathArg(file_id) - ) - } else { - format!( - "/organizations/{}/releases/{}/files/{}/?download=1", - PathArg(org), - PathArg(version), - PathArg(file_id) - ) - }; - - let resp = self.api.download(&path, file_desc)?; - if resp.status() == 404 { - resp.convert_rnf(ApiErrorKind::ResourceNotFound) - } else { - Ok(()) - } - } - - /// Get a single release file metadata. - pub fn get_release_file_metadata( - &self, - org: &str, - project: Option<&str>, - version: &str, - file_id: &str, - ) -> ApiResult> { - let path = if let Some(project) = project { - format!( - "/projects/{}/{}/releases/{}/files/{}/", - PathArg(org), - PathArg(project), - PathArg(version), - PathArg(file_id) - ) - } else { - format!( - "/organizations/{}/releases/{}/files/{}/", - PathArg(org), - PathArg(version), - PathArg(file_id) - ) - }; - - let resp = self.get(&path)?; - if resp.status() == 404 { - Ok(None) - } else { - resp.convert() - } - } - /// Deletes a single release file. Returns `true` if the file was /// deleted or `false` otherwise. pub fn delete_release_file( @@ -1302,37 +1238,6 @@ impl<'a> AuthenticatedApi<'a> { Ok(rv) } - /// Looks up an event, which was already processed by Sentry and returns it. - /// If it does not exist `None` will be returned. - pub fn get_event( - &self, - org: &str, - project: Option<&str>, - event_id: &str, - ) -> ApiResult> { - let path = if let Some(project) = project { - format!( - "/projects/{}/{}/events/{}/json/", - PathArg(org), - PathArg(project), - PathArg(event_id) - ) - } else { - format!( - "/organizations/{}/events/{}/json/", - PathArg(org), - PathArg(event_id) - ) - }; - - let resp = self.get(&path)?; - if resp.status() == 404 { - Ok(None) - } else { - resp.convert() - } - } - fn get_region_url(&self, org: &str) -> ApiResult { self.get(&format!("/organizations/{org}/region/")) .and_then(|resp| resp.convert::()) @@ -2383,12 +2288,6 @@ pub struct ProcessedEvent { #[expect(dead_code)] pub project: Option, #[serde(default, skip_serializing_if = "Option::is_none")] - pub release: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub dist: Option, - #[serde(default, skip_serializing_if = "Values::is_empty")] - pub exception: Values, - #[serde(default, skip_serializing_if = "Option::is_none")] pub user: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub tags: Option>, diff --git a/src/commands/sourcemaps/explain.rs b/src/commands/sourcemaps/explain.rs deleted file mode 100644 index 2e04a0ee3b..0000000000 --- a/src/commands/sourcemaps/explain.rs +++ /dev/null @@ -1,521 +0,0 @@ -#![expect(clippy::unwrap_used, reason = "deprecated command")] - -use std::io::Read as _; -use std::path::Path; - -use anyhow::{bail, format_err, Result}; -use clap::{Arg, ArgAction, ArgMatches, Command}; -use console::style; -use sentry::protocol::{Frame, Stacktrace}; -use url::Url; - -use crate::api::{Api, Artifact, ProcessedEvent}; -use crate::config::Config; -use crate::utils::fs::TempFile; -use crate::utils::system::QuietExit; - -use super::resolve::print_source; - -pub fn make_command(command: Command) -> Command { - command - .about("[DEPRECATED] Explain why sourcemaps are not working for a given event.") - .hide(true) - .alias("why") - .arg( - Arg::new("event") - .value_name("EVENT_ID") - .required(true) - .help("ID of an event to be explained."), - ) - .arg( - Arg::new("frame") - .long("frame") - .default_value("0") - .value_parser(clap::value_parser!(usize)) - .help("Position of the frame that should be used for source map resolution."), - ) - .arg( - Arg::new("force") - .long("force") - .short('f') - .action(ArgAction::SetTrue) - .help("Force full validation flow, even when event is already source mapped."), - ) -} - -fn tip(msg: S) -where - S: std::fmt::Display, -{ - println!("{}", style(format!("ℹ {msg}")).blue()); -} - -fn success(msg: S) -where - S: std::fmt::Display, -{ - println!("{}", style(format!("✔ {msg}")).green()); -} - -fn warning(msg: S) -where - S: std::fmt::Display, -{ - println!("{}", style(format!("⚠ {msg}")).yellow()); -} - -fn error(msg: S) -where - S: std::fmt::Display, -{ - println!("{}", style(format!("✖ {msg}")).red()); -} - -fn fetch_event(org: &str, project: &str, event_id: &str) -> Result { - match Api::current() - .authenticated()? - .get_event(org, Some(project), event_id)? - { - Some(event) => { - success(format!("Fetched data for event: {event_id}")); - Ok(event) - } - None => { - error(format!("Could not retrieve event {event_id}")); - tip("Make sure that event ID you used is valid."); - Err(QuietExit(1).into()) - } - } -} - -fn extract_in_app_frames(stacktrace: &Stacktrace) -> Vec<&Frame> { - stacktrace - .frames - .iter() - .filter(|frame| frame.in_app.unwrap_or(false)) - .collect() -} - -fn extract_nth_frame(stacktrace: &Stacktrace, position: usize) -> Result<&Frame> { - let mut in_app_frames = extract_in_app_frames(stacktrace); - - if in_app_frames.is_empty() { - bail!("Event exception stacktrace has no in_app frames"); - } - - // Frames are in bottom-up order. - in_app_frames.reverse(); - - let frame = in_app_frames - .get(position) - .ok_or_else(|| format_err!("Selected frame ({position}) is missing."))?; - - let abs_path = frame - .abs_path - .as_ref() - .ok_or_else(|| format_err!("Selected frame ({position}) is missing an abs_path"))?; - - if let Ok(abs_path) = Url::parse(abs_path) { - if Path::new(abs_path.path()).extension().is_none() { - bail!("Selected frame ({position}) of event exception originates from the