diff --git a/.craft.yml b/.craft.yml index 56e81e4ab2..0b9c80d94a 100644 --- a/.craft.yml +++ b/.craft.yml @@ -1,5 +1,6 @@ minVersion: 0.23.1 changelogPolicy: auto +postReleaseCommand: bash scripts/post-release.sh targets: - name: gcs bucket: sentry-sdk-assets diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09f95c9941..6b5e2bfaa7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,8 @@ jobs: test_node: name: Test Node uses: ./.github/workflows/test_node.yml + with: + triggered-by-release: ${{ github.event_name == 'push' && startsWith(github.ref_name, 'release/') }} test_swift: name: Test Swift diff --git a/.github/workflows/test_node.yml b/.github/workflows/test_node.yml index a7a42c1163..848bb43121 100644 --- a/.github/workflows/test_node.yml +++ b/.github/workflows/test_node.yml @@ -2,6 +2,11 @@ name: Test Node on: workflow_call: + inputs: + triggered-by-release: + type: boolean + description: Whether the workflow was triggered by a release + default: false outputs: matrix-result: description: 'Matrix job result' @@ -19,10 +24,16 @@ jobs: with: node-version-file: package.json - # We need to skip the fallback download because downloading will fail on release branches because the new version isn't available yet. - # We have to use npm here because yarn fails on the non-existing existing optionalDependency version: - # https://github.com/yarnpkg/berry/issues/2425#issuecomment-1627807326 - - run: SENTRYCLI_SKIP_DOWNLOAD=1 npm ci + - name: Install dependencies via npm ci + if: ${{ !inputs.triggered-by-release }} + run: npm ci + + # For pushes to the release branch, we need to install the dependencies via `npm install` + # because the `package-lock.json` is not updated with the new versions of the optional + # dependencies yet. We also must skip the fallback download via --ignore-scripts. + - name: Install dependencies via npm install (for pushes to release branch) + if: ${{ inputs.triggered-by-release }} + run: npm install --omit=optional --ignore-scripts - run: npm run check:types @@ -43,10 +54,16 @@ jobs: with: node-version: ${{ matrix.node-version }} - # We need to skip the fallback download because downloading will fail on release branches because the new version isn't available yet. - # We have to use npm here because yarn fails on the non-existing existing optionalDependency version: - # https://github.com/yarnpkg/berry/issues/2425#issuecomment-1627807326 - - run: SENTRYCLI_SKIP_DOWNLOAD=1 npm ci + - name: Install dependencies via npm ci + if: ${{ !inputs.triggered-by-release }} + run: npm ci + + # For pushes to the release branch, we need to install the dependencies via `npm install` + # because the `package-lock.json` is not updated with the new versions of the optional + # dependencies yet. We also must skip the fallback download via --ignore-scripts. + - name: Install dependencies via npm install (for pushes to release branch) + if: ${{ inputs.triggered-by-release }} + run: npm install --omit=optional --ignore-scripts # older node versions need an older nft - run: SENTRYCLI_SKIP_DOWNLOAD=1 npm install @vercel/nft@0.22.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index f5716e6380..5bad9617b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ "You know what they say. Fool me once, strike one, but fool me twice... strike three." — Michael Scott +## 2.54.0 + +### Various fixes & improvements + +- Fix: symlinks in normalized upload (#2744) by @noahsmartin +- feat(vcs): Prefer upstream remote over origin for base repo name (#2737) by @runningcode +- feat(build): Add auto-detection of base_repo_name from git remote (#2735) by @runningcode +- feat(build): Add auto-detection of PR number from GitHub Actions (#2722) by @runningcode +- feat(build): Auto-detect base_ref from git merge-base (#2720) by @runningcode +- feat(logs): support log streaming (#2666) by @vgrozdanic + ## 2.53.0 ### Various fixes & improvements @@ -22,7 +33,7 @@ Please note, the `build` commands are still experimental, and are therefore subj ## 2.53.0-alpha -This release reintroduces the `build` (previously named `mobile-app`) commands. +This release reintroduces the `build` (previously named `mobile-app`) commands. ### Various fixes & improvements diff --git a/Cargo.lock b/Cargo.lock index 0de926a2eb..f215718d11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "sentry-cli" -version = "2.53.0" +version = "2.54.0" dependencies = [ "anyhow", "anylog", diff --git a/Cargo.toml b/Cargo.toml index e78eb975f7..2e9ebcf4f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Armin Ronacher "] build = "build.rs" name = "sentry-cli" -version = "2.53.0" +version = "2.54.0" edition = "2021" rust-version = "1.86" 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 ab6c1d0577..d69c666029 100644 --- a/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift +++ b/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift @@ -84,7 +84,9 @@ enum AssetUtil { key.perform(Selector(("keyList"))), to: UnsafeMutableRawPointer.self ) - let rendition = createRendition(from: structuredThemeStore, keyList) + guard let rendition = createRendition(from: structuredThemeStore, keyList) else { + continue + } let data = rendition.value(forKey: "_srcData") as! Data let length = UInt(data.count) @@ -198,13 +200,13 @@ enum AssetUtil { } private static func createRendition(from themeStore: NSObject, _ keyList: UnsafeMutableRawPointer) - -> NSObject + -> NSObject? { let renditionWithKeySelector = Selector(("renditionWithKey:")) let renditionWithKeyMethod = themeStore.method(for: renditionWithKeySelector)! let renditionWithKeyImp = unsafeBitCast(renditionWithKeyMethod, to: objectiveCMethodImp.self) - return renditionWithKeyImp(themeStore, renditionWithKeySelector, keyList)!.takeUnretainedValue() - as! NSObject + return renditionWithKeyImp(themeStore, renditionWithKeySelector, keyList)?.takeUnretainedValue() + as? NSObject } private static func handleReferenceKey( @@ -222,7 +224,9 @@ enum AssetUtil { referenceKey.perform(Selector(("keyList"))), to: UnsafeMutableRawPointer.self ) - let referenceRendition = createRendition(from: themeStore, referenceKeyList) + guard let referenceRendition = createRendition(from: themeStore, referenceKeyList) else { + return false + } if let result = referenceRendition.perform(Selector(("unslicedImage"))) { let image = result.takeUnretainedValue() as! CGImage diff --git a/npm-binary-distributions/darwin/package.json b/npm-binary-distributions/darwin/package.json index 61304d2356..ab812d0cd5 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.53.0", + "version": "2.54.0", "description": "The darwin distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/linux-arm/package.json b/npm-binary-distributions/linux-arm/package.json index 2f42411b98..aceabe6c23 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.53.0", + "version": "2.54.0", "description": "The linux arm distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/linux-arm64/package.json b/npm-binary-distributions/linux-arm64/package.json index 1f6f8b3318..27b3365a55 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.53.0", + "version": "2.54.0", "description": "The linux arm64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/linux-i686/package.json b/npm-binary-distributions/linux-i686/package.json index 2b2771ef55..76c510d2ba 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.53.0", + "version": "2.54.0", "description": "The linux x86 and ia32 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/linux-x64/package.json b/npm-binary-distributions/linux-x64/package.json index d002208f39..7dbfd28856 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.53.0", + "version": "2.54.0", "description": "The linux x64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/win32-arm64/package.json b/npm-binary-distributions/win32-arm64/package.json index 0e47eeb9a6..e2292d4677 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.53.0", + "version": "2.54.0", "description": "The windows arm64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/win32-i686/package.json b/npm-binary-distributions/win32-i686/package.json index b3b6998b12..40905190ad 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.53.0", + "version": "2.54.0", "description": "The windows x86 and ia32 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/npm-binary-distributions/win32-x64/package.json b/npm-binary-distributions/win32-x64/package.json index 71a3c2d653..f773a4c6d1 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.53.0", + "version": "2.54.0", "description": "The windows x64 distribution of the Sentry CLI binary.", "repository": "https://github.com/getsentry/sentry-cli", "license": "BSD-3-Clause", diff --git a/package-lock.json b/package-lock.json index 6131ae6dfa..cabc441493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli", - "version": "2.53.0", + "version": "2.54.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -767,51 +767,51 @@ } }, "@sentry/cli-darwin": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.53.0.tgz", - "integrity": "sha512-NNPfpILMwKgpHiyJubHHuauMKltkrgLQ5tvMdxNpxY60jBNdo5VJtpESp4XmXlnidzV4j1z61V4ozU6ttDgt5Q==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.54.0.tgz", + "integrity": "sha512-bQZCC6vLtlnOlDUBZdvvO3Hbzf3keAOI9Ho3IPooaUtkwkKmJbHkOprMJ8WuEDb8JyUOBMFLT7T83bWA7CBJow==", "optional": true }, "@sentry/cli-linux-arm": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.53.0.tgz", - "integrity": "sha512-NdRzQ15Ht83qG0/Lyu11ciy/Hu/oXbbtJUgwzACc7bWvHQA8xEwTsehWexqn1529Kfc5EjuZ0Wmj3MHmp+jOWw==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.54.0.tgz", + "integrity": "sha512-Brx/MsIBXmMuP/rRZos8pMxW5mSZoYmR0tDO483RR9hfE6PnyxhvNOTkLLm6fMd3pGmiG4sr25jYeYQglhIpRA==", "optional": true }, "@sentry/cli-linux-arm64": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.53.0.tgz", - "integrity": "sha512-xY/CZ1dVazsSCvTXzKpAgXaRqfljVfdrFaYZRUaRPf1ZJRGa3dcrivoOhSIeG/p5NdYtMvslMPY9Gm2MT0M83A==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.54.0.tgz", + "integrity": "sha512-ocE6gBD2GiMH8Vm0OdlD8tz9eq4uiTmG2Nb0sQshcTDZ7DkOGEmtbg2Je2F1Eug6wR/zQWzD/t0bMUm6L0X0Rg==", "optional": true }, "@sentry/cli-linux-i686": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.53.0.tgz", - "integrity": "sha512-0REmBibGAB4jtqt9S6JEsFF4QybzcXHPcHtJjgMi5T0ueh952uG9wLzjSxQErCsxTKF+fL8oG0Oz5yKBuCwCCQ==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.54.0.tgz", + "integrity": "sha512-GZyLbZjDX8e635O8iVbzkHs9KGUo5UK0PGbTsjxlKHNgWAf1SY+y+wtWLrF46AhxUveeV/ydEUOJJjcDgXW3+g==", "optional": true }, "@sentry/cli-linux-x64": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.53.0.tgz", - "integrity": "sha512-9UGJL+Vy5N/YL1EWPZ/dyXLkShlNaDNrzxx4G7mTS9ywjg+BIuemo6rnN7w43K1NOjObTVO6zY0FwumJ1pCyLg==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.54.0.tgz", + "integrity": "sha512-NyTM6dp+/cFiULUTGlxlaa83pL+FdWHwPE5IkQ6EiqpsO0auacVwWJIIvj4EbFS7XQ8bgjUA3Rf83lZeI+ZPvQ==", "optional": true }, "@sentry/cli-win32-arm64": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.53.0.tgz", - "integrity": "sha512-G1kjOjrjMBY20rQcJV2GA8KQE74ufmROCDb2GXYRfjvb1fKAsm4Oh8N5+Tqi7xEHdjQoLPkE4CNW0aH68JSUDQ==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.54.0.tgz", + "integrity": "sha512-oVsdo7yWAokGtnl2cbuxvPv3Pu3ge8n9Oyp+iNT1S98XJ/QtRGT8L2ZClNllzEeVFFoZWlK7RVT5xh7OI4ge/w==", "optional": true }, "@sentry/cli-win32-i686": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.53.0.tgz", - "integrity": "sha512-qbGTZUzesuUaPtY9rPXdNfwLqOZKXrJRC1zUFn52hdo6B+Dmv0m/AHwRVFHZP53Tg1NCa8bDei2K/uzRN0dUZw==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.54.0.tgz", + "integrity": "sha512-YvBUq5ky80j2fulllft6ZCtLslwrNc5s8dXV7Jr7IUUmTcVcvkOdgWwAsGRjTmZxXZbfaRaYE2fEvfFwjmciTA==", "optional": true }, "@sentry/cli-win32-x64": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.53.0.tgz", - "integrity": "sha512-1TXYxYHtwgUq5KAJt3erRzzUtPqg7BlH9T7MdSPHjJatkrr/kwZqnVe2H6Arr/5NH891vOlIeSPHBdgJUAD69g==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.54.0.tgz", + "integrity": "sha512-Jn5abpRrbdcQrec+8QTgGdX8wxTdQr4bm81I/suJ3bXpID+fsiAnp+yclKlq8LWlj5q7uATnGJ4QpajDT9qBRQ==", "optional": true }, "@sinonjs/commons": { diff --git a/package.json b/package.json index 328115642b..44732f13b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cli", - "version": "2.53.0", + "version": "2.54.0", "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.53.0", - "@sentry/cli-linux-arm": "2.53.0", - "@sentry/cli-linux-arm64": "2.53.0", - "@sentry/cli-linux-i686": "2.53.0", - "@sentry/cli-linux-x64": "2.53.0", - "@sentry/cli-win32-i686": "2.53.0", - "@sentry/cli-win32-x64": "2.53.0", - "@sentry/cli-win32-arm64": "2.53.0" + "@sentry/cli-darwin": "2.54.0", + "@sentry/cli-linux-arm": "2.54.0", + "@sentry/cli-linux-arm64": "2.54.0", + "@sentry/cli-linux-i686": "2.54.0", + "@sentry/cli-linux-x64": "2.54.0", + "@sentry/cli-win32-i686": "2.54.0", + "@sentry/cli-win32-x64": "2.54.0", + "@sentry/cli-win32-arm64": "2.54.0" }, "scripts": { "postinstall": "node ./scripts/install.js", diff --git a/scripts/post-release.sh b/scripts/post-release.sh new file mode 100644 index 0000000000..03bf6fa436 --- /dev/null +++ b/scripts/post-release.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# This script is run by Craft after a release is created. +# We currently use it to bump the platform-specific optional dependencies to their new versions +# in the package-lock.json, immediately after a release is created. This is needed for CI to +# pass after the release is created.c + +set -eux +OLD_VERSION="${1}" +NEW_VERSION="${2}" + +git checkout master + +# We need to update the package-lock.json to include the new version of the optional dependencies. +npm install --package-lock-only --ignore-scripts + +git add package-lock.json + +# Only commit if there are changes +git diff --staged --quiet || git commit -m "build(npm): 🤖 Bump optional dependencies to ${NEW_VERSION}" +git pull --rebase +git push diff --git a/src/commands/build/upload.rs b/src/commands/build/upload.rs index 81be6fc1b2..260767b4b0 100644 --- a/src/commands/build/upload.rs +++ b/src/commands/build/upload.rs @@ -325,7 +325,8 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { } ); for (path, reason) in errored_paths_and_reasons { - warn!(" - {} ({})", path.display(), reason); + warn!(" - {}", path.display()); + warn!(" Error: {reason:#}"); } } diff --git a/src/commands/releases/set_commits.rs b/src/commands/releases/set_commits.rs index c227913701..81b462d82f 100644 --- a/src/commands/releases/set_commits.rs +++ b/src/commands/releases/set_commits.rs @@ -5,8 +5,9 @@ use clap::{Arg, ArgAction, ArgMatches, Command}; use lazy_static::lazy_static; use regex::Regex; -use crate::api::{Api, NewRelease, NoneReleaseInfo, OptionalReleaseInfo, UpdatedRelease}; +use crate::api::{Api, NewRelease, NoneReleaseInfo, OptionalReleaseInfo, Ref, UpdatedRelease}; use crate::config::Config; +use crate::constants::MAX_COMMIT_SHA_LENGTH; use crate::utils::args::ArgExt as _; use crate::utils::formatting::Table; use crate::utils::vcs::{ @@ -53,19 +54,16 @@ pub fn make_command(command: Command) -> Command { .short('c') .value_name("SPEC") .action(ArgAction::Append) - .help("Defines a single commit for a repo as \ + .help(format!("Defines a single commit for a repo as \ identified by the repo name in the remote Sentry config. \ - If no commit has been specified sentry-cli will attempt \ - to auto discover that repository in the local git repo \ - and then use the HEAD commit. This will either use the \ - current git repository or attempt to auto discover a \ - submodule with a compatible URL.\n\n\ - The value can be provided as `REPO` in which case sentry-cli \ - will auto-discover the commit based on reachable repositories. \ - Alternatively it can be provided as `REPO#PATH` in which case \ - the current commit of the repository at the given PATH is \ - assumed. To override the revision `@REV` can be appended \ - which will force the revision to a certain value.")) + The value must be provided as `REPO@SHA` where SHA is \ + at most {MAX_COMMIT_SHA_LENGTH} characters. To specify a range, use `REPO@PREV_SHA..SHA` \ + format.\n\n\ + Note: You must specify a previous commit when setting commits for the first release.\n\n\ + Examples:\ + \n - `my-repo@abc123` (partial SHA)\ + \n - `my-repo@62aaca3ed186edc7671b4cca0ab6ec53cb7de8b5` (full SHA)\ + \n - `my-repo@abc123..def456` (commit range)"))) // Legacy flag that has no effect, left hidden for backward compatibility .arg(Arg::new("ignore-empty") .long("ignore-empty") @@ -83,6 +81,7 @@ fn strip_sha(sha: &str) -> &str { sha } } + pub fn execute(matches: &ArgMatches) -> Result<()> { let config = Config::current(); let api = Api::current(); @@ -90,7 +89,6 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { let version = matches.get_one::("version").unwrap(); let org = config.get_org(matches)?; let repos = authenticated_api.list_organization_repos(&org)?; - let mut commit_specs = vec![]; let heads = if repos.is_empty() { None @@ -105,30 +103,49 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { Some(vec![]) } else if matches.get_flag("local") { None - } else { - if let Some(commits) = matches.get_many::("commits") { - for spec in commits { - let commit_spec = CommitSpec::parse(spec)?; - if repos - .iter() - .any(|r| r.name.to_lowercase() == commit_spec.repo.to_lowercase()) - { - commit_specs.push(commit_spec); - } else { - bail!("Unknown repo '{}'", commit_spec.repo); + } else if let Some(commits) = matches.get_many::("commits") { + let mut refs = vec![]; + for spec in commits { + let commit_spec = CommitSpec::parse(spec)?; + + if !repos + .iter() + .any(|r| r.name.to_lowercase() == commit_spec.repo.to_lowercase()) + { + bail!("Unknown repo '{}'", commit_spec.repo); + } + + if commit_spec.rev.len() > MAX_COMMIT_SHA_LENGTH { + bail!( + "Invalid commit SHA '{}'. Commit SHAs must be {} characters or less.", + commit_spec.rev, + MAX_COMMIT_SHA_LENGTH + ); + } + + if let Some(ref prev_rev) = commit_spec.prev_rev { + if prev_rev.len() > MAX_COMMIT_SHA_LENGTH { + bail!( + "Invalid previous commit SHA '{}'. Commit SHAs must be {} characters or less.", + prev_rev, + MAX_COMMIT_SHA_LENGTH + ); } } + + refs.push(Ref { + repo: commit_spec.repo, + rev: commit_spec.rev, + prev_rev: commit_spec.prev_rev, + }); } - let commits = find_heads( - Some(commit_specs), - &repos, - Some(config.get_cached_vcs_remote()), - )?; - if commits.is_empty() { + if refs.is_empty() { None } else { - Some(commits) + Some(refs) } + } else { + None }; // make sure the release exists if projects are given diff --git a/src/constants.rs b/src/constants.rs index 8a300e883a..ee6a76ffa7 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -47,5 +47,7 @@ pub const DEFAULT_MAX_DIF_ITEM_SIZE: u64 = 1024 * 1024; // 1MB pub const DEFAULT_MAX_DIF_UPLOAD_SIZE: u64 = 35 * 1024 * 1024; // 35MB /// Default maximum time to wait for file assembly. pub const DEFAULT_MAX_WAIT: Duration = Duration::from_secs(5 * 60); +/// Maximum length for commit SHA values, enforced in backend. +pub const MAX_COMMIT_SHA_LENGTH: usize = 64; include!(concat!(env!("OUT_DIR"), "/constants.gen.rs")); diff --git a/src/utils/vcs.rs b/src/utils/vcs.rs index 2ec789f0e4..07cc944219 100644 --- a/src/utils/vcs.rs +++ b/src/utils/vcs.rs @@ -207,6 +207,11 @@ impl VcsUrl { } } +fn extract_provider_name(host: &str) -> &str { + let trimmed = host.trim_end_matches('.'); + trimmed.rsplit('.').nth(1).unwrap_or(trimmed) +} + fn is_matching_url(a: &str, b: &str) -> bool { VcsUrl::parse(a) == VcsUrl::parse(b) } @@ -218,7 +223,7 @@ pub fn get_repo_from_remote(repo: &str) -> String { pub fn get_provider_from_remote(remote: &str) -> String { let obj = VcsUrl::parse(remote); - obj.provider + extract_provider_name(&obj.provider).to_owned() } pub fn git_repo_remote_url( @@ -922,6 +927,63 @@ mod tests { ); } + #[test] + fn test_extract_provider_name() { + // Test basic provider name extraction + assert_eq!(extract_provider_name("github.com"), "github"); + assert_eq!(extract_provider_name("gitlab.com"), "gitlab"); + assert_eq!(extract_provider_name("bitbucket.org"), "bitbucket"); + + // Test edge case with trailing dots + assert_eq!(extract_provider_name("github.com."), "github"); + + // Test subdomain cases - we want the part before TLD, not the subdomain + assert_eq!(extract_provider_name("api.github.com"), "github"); + assert_eq!(extract_provider_name("ssh.dev.azure.com"), "azure"); + assert_eq!(extract_provider_name("dev.azure.com"), "azure"); + + // Test single component (no dots) + assert_eq!(extract_provider_name("localhost"), "localhost"); + assert_eq!(extract_provider_name("myserver"), "myserver"); + + // Test empty string + assert_eq!(extract_provider_name(""), ""); + } + + #[test] + fn test_get_provider_from_remote() { + // Test that get_provider_from_remote normalizes provider names + assert_eq!( + get_provider_from_remote("https://github.com/user/repo"), + "github" + ); + assert_eq!( + get_provider_from_remote("git@gitlab.com:user/repo.git"), + "gitlab" + ); + assert_eq!( + get_provider_from_remote("https://bitbucket.org/user/repo"), + "bitbucket" + ); + assert_eq!( + get_provider_from_remote("https://dev.azure.com/user/repo"), + "azure" + ); + assert_eq!( + get_provider_from_remote("https://github.mycompany.com/user/repo"), + "mycompany" + ); + assert_eq!( + get_provider_from_remote("https://source.developers.google.com/p/project/r/repo"), + "google" + ); + // Test edge case with trailing dot in hostname + assert_eq!( + get_provider_from_remote("https://github.com./user/repo"), + "github" + ); + } + #[test] fn test_url_normalization() { assert!(!is_matching_url(