Dashboard › cli › Distillation
fa26922b-62e1-4725-86ed-ec60ed508c3a["lore_tm_v1_ZxXsfL-Sn5hsEhnaVZ9oLBeHK3zqPYWmCGXH31URIAk","lore_tm_v1_5B0jSAXtgEFTe7YViXI4MvANu5r0M_b5TRRURp5BZ38","lore_tm_v1_7AmnydyT_fxo4v8ANQhZj0duvX8dYBqBiwBHVXTJno4","lore_tm_v1_arcBRq0JSWIxqkdWHkoMfBHNrSY5ZTWWfC00MjYwyZQ"]
Date: September 9, 2026
resolveStableChain() coverage in packages/cli/test/lib/delta-upgrade.test.ts: resolving "0.13.0" β "0.14.0" returns null; a generated sequence of 15 releases representing 14 hops from "0.1.0" β "0.15.0" returns null because it exceeds MAX_STABLE_CHAIN_DEPTH (10).setupNightlyMocks() in packages/cli/test/lib/delta-upgrade.test.ts, mocking GHCR token exchange, /tags/list, manifest lookup, and blob downloads with a manual 307 redirect to https://blob.test/<digest>, followed by serving the matching Uint8Array.resolveNightlyChain() single-hop coverage: "0.0.0-dev.100" β "0.0.0-dev.101" uses patch bytes [99, 88, 77], digest "sha256:aabbccdd1122334455", and expected SHA-256 "aabb1122"; the result has 1 patch and the exact step { fromVersion: "0.0.0-dev.100", toVersion: "0.0.0-dev.101" }.resolveNightlyChain() rejection coverage: no matching patch graph returns null; 35 tags from patch-0.0.0-dev.101 through patch-0.0.0-dev.135 return null because they exceed MAX_NIGHTLY_CHAIN_DEPTH (30); mismatched "from-version" linkage, a manifest-fetch 404, a chain ending before the requested target, a missing target SHA-256 annotation, and a patch layer titled "wrong-name.patch" all return null.90_000-byte layer is rejected against fullGzSize: 100_000 because it exceeds the 0.6 budget (60_000 bytes).resolveNightlyChain() multi-hop coverage: patches [10, 20] and [30, 40], digests "sha256:aaaa1111" and "sha256:bbbb2222", resolve "0.0.0-dev.100" β "0.0.0-dev.101" β "0.0.0-dev.102"; the result has 2 patches in order and expected SHA-256 "finalhash".applyPatchChain() keeps intermediate hops in memory; legacy scratch files ${destPath}.patching.a and ${destPath}.patching.b must never be written, and the in-memory chain never creates scratch files on disk.applyPatchChain() filesystem tests using fixtures under test/fixtures/patches: "small-old.bin", "small-new.bin", and "small.trdiff10". Tests verify a single patch produces the expected bytes and SHA-256, an all-zero 64-character expected hash throws "SHA-256 mismatch", and the resulting output file is readable.applyPatchChain() no-scratch-file test reusing "small.trdiff10" twice: the first application produces valid bytes, the second operates on mismatched bytes and may fail final-hash verification, but neither .patching.a nor .patching.b may exist afterward.packages/cli/test/lib/delta-upgrade.test.ts: resolveStableDelta("0.14.0", "/tmp/fake-old", "/tmp/fake-out") returns null when test CLI_VERSION is "0.0.0-dev"; attemptDeltaUpgrade() likewise returns null when canAttemptDelta() is false.resolveNightlyDelta() tests requiring null when GHCR token retrieval returns HTTP 401, when no patch tags match the range, or when the target OCI manifest lacks the ${BINARY_NAME_ND}.gz layer needed to determine the size threshold.prefetchNightlyPatches("0.14.0-dev.123") and prefetchStablePatches("0.14.0") return immediately without calling fetch when test CLI_VERSION is "0.0.0-dev".resolveChannelAndVersion() in packages/cli/src/commands/cli/upgrade.ts: positional "nightly" and "stable" are matched case-insensitively as release-channel selectors with versionArg: undefined; other values retain getReleaseChannel() and become the version argument.packages/cli/src/commands/cli/upgrade.ts: an explicit version bypasses cache lookup after removing VERSION_PREFIX_REGEX; otherwise getVersionCheckInfo().latestVersion is used, and absence of a cached version throws UpgradeError("network_error", "No cached version available. Run any command to trigger a background version check, then retry.").resolveTargetWithFallback() behavior: explicit --offline cannot switch channels without a pinned version because the cached version belongs to the current channel; cached target resolution occurs before persistChannelFn() because setReleaseChannel clears the version cache on channel changes.UpgradeError reason "network_error"; it logs "Network unavailable, falling back to cached upgrade target", uses the cached target when available, and rethrows the original network error if cache resolution also fails.resolveTargetVersion() implements this with const lookupMethod = channel === "nightly" ? "curl" : method.resolveTargetVersion() behavior in packages/cli/src/commands/cli/upgrade.ts: it fetches the latest version with fetchLatestVersion(method, channel), strips VERSION_PREFIX_REGEX from a pinned version, returns a structured "checked" result for flags.check, returns "up-to-date" when CLI_VERSION === target unless forced or changing channel, and throws UpgradeError("version_not_found", \Version ${target} not found`) when versionExists() fails.buildCheckResult() emits action: "checked", currentVersion, targetVersion, channel, method, and forced; when the target differs, its warning is either Run 'sentry cli upgrade <target>' to update. for a pinned version or Run 'sentry cli upgrade' to update. otherwise.packages/cli/src/commands/cli/upgrade.ts: SPAWN_MAX_ATTEMPTS = 5, SPAWN_RETRY_BASE_MS = 500, delay is attempt * SPAWN_RETRY_BASE_MS, and retries occur only for EBUSY errors caused by Defender/SmartScreen potentially locking a newly written executable.isEbusyError() recognizes NodeJS.ErrnoException.code === "EBUSY"; isEnoentSpawnError() recognizes code === "ENOENT" and the legacy message substring "Executable not found in $PATH".spawnWithRetry() error handling: macOS SIGKILL becomes UpgradeError("execution_failed", ...) with reinstall guidance curl -sL https://sentry.io/get-cli/ | bash; missing downloaded binaries become an actionable UpgradeError instructing users to rerun sentry cli upgrade; non-EBUSY errors are thrown immediately, and exhausting all retries throws "Spawn retry loop exhausted".runSetupOnNewBinary() invokes the new binary with ordered arguments "cli", "setup", "--quiet", "--method", method, "--channel", channel, and "--no-modify-path"; it conditionally adds "--install", "--ensure-auth-scopes", and "--no-agent-skills", pins SENTRY_INSTALL_DIR when installDir is provided, and throws UpgradeError("execution_failed", \Setup failed with exit code ${exitCode}`)` for a nonzero exit.resolveUpdatedCliPath() resolves the updated executable as whichSync("sentry", { PATH: pathEnv }) ?? entryPath ?? execPath.resolveUpgradeInstallDir() behavior: curl upgrades normally remain in the current install directory; legacy ~/.sentry/bin installs move to the XDG-aligned directory only when that directory differs from the legacy path and is already on PATH, otherwise they stay in place.executeStandardUpgrade() behavior: latest-nightly upgrades use the rolling NIGHTLY_TAG, while pinned nightly versions use their own tag; downloads run through withProgress() and executeUpgrade(); successful deltas log downloaded patch bytes via formatBytes().install: true, a pinned install directory from resolveUpgradeInstallDir(), ensureAuthScopes: !json, and noAgentSkills; releaseLock(downloadResult.lockPath) runs in finally.resolveUpdatedCliPath(execPath, entryPath, pathEnv) with install: false, ensuring it uses the replaced CLI rather than Nodeβs process.execPath or a removed Homebrew keg path.