diff --git a/.github/workflows/ci_bindings_nodejs.yml b/.github/workflows/ci_bindings_nodejs.yml index 44bc04303883..52cf61fe2e5f 100644 --- a/.github/workflows/ci_bindings_nodejs.yml +++ b/.github/workflows/ci_bindings_nodejs.yml @@ -19,14 +19,14 @@ name: Bindings NodeJS CI env: DEBUG: napi:* - MACOSX_DEPLOYMENT_TARGET: '10.13' + MACOSX_DEPLOYMENT_TARGET: "10.13" on: push: branches: - main tags: - - '*' + - "*" pull_request: branches: - main @@ -57,12 +57,12 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: "18" cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies run: pnpm install --frozen-lockfile @@ -99,7 +99,7 @@ jobs: -e NAPI_TARGET=x86_64-unknown-linux-gnu \ -w /build/bindings/nodejs \ ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian \ - bash -c "corepack enable && pnpm build" + bash -c "npm i -g --force corepack && corepack enable && pnpm build" cd bindings/nodejs # change owner to current user sudo chown -R 1001:121 *.node @@ -112,6 +112,7 @@ jobs: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 \ bash -c "set -e && rustup target add aarch64-unknown-linux-gnu && + npm i -g --force corepack && corepack enable && pnpm build --target aarch64-unknown-linux-gnu && aarch64-unknown-linux-gnu-strip *.node" @@ -127,6 +128,7 @@ jobs: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine \ bash -c "set -e && rustup target add aarch64-unknown-linux-musl && + npm i -g --force corepack && corepack enable && pnpm build --target aarch64-unknown-linux-musl && /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node" @@ -142,11 +144,11 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: "18" cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build @@ -191,11 +193,11 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: "18" cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build @@ -247,7 +249,7 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: "18" cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack @@ -265,7 +267,7 @@ jobs: release: name: Release runs-on: ubuntu-latest - needs: [ macos, linux, windows ] + needs: [macos, linux, windows] permissions: id-token: write @@ -286,7 +288,7 @@ jobs: cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/ci_check.yml b/.github/workflows/ci_check.yml index 0c4ed1e5522a..ca0efade6e64 100644 --- a/.github/workflows/ci_check.yml +++ b/.github/workflows/ci_check.yml @@ -103,7 +103,7 @@ jobs: - name: Corepack working-directory: website - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install Dependencies working-directory: website diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 002a9f28ea75..ce337eba68d2 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -116,7 +116,7 @@ jobs: cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack working-directory: bindings/nodejs - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies working-directory: bindings/nodejs @@ -521,7 +521,7 @@ jobs: - name: Corepack working-directory: website - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Download rust docs uses: actions/download-artifact@v4 diff --git a/.github/workflows/test_behavior_binding_nodejs.yml b/.github/workflows/test_behavior_binding_nodejs.yml index 510fbe40401e..7a9896e49fa0 100644 --- a/.github/workflows/test_behavior_binding_nodejs.yml +++ b/.github/workflows/test_behavior_binding_nodejs.yml @@ -61,13 +61,13 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: '18' + node-version: "18" cache: pnpm cache-dependency-path: "bindings/nodejs/pnpm-lock.yaml" - name: Corepack working-directory: bindings/nodejs - run: corepack enable + run: npm i -g --force corepack && corepack enable - name: Install dependencies working-directory: bindings/nodejs diff --git a/bin/oay/Cargo.lock b/bin/oay/Cargo.lock index 4f23b0353ba6..0a9f5383338e 100644 --- a/bin/oay/Cargo.lock +++ b/bin/oay/Cargo.lock @@ -899,9 +899,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "logforth" diff --git a/bin/oay/Cargo.toml b/bin/oay/Cargo.toml index 22223ec14f40..c505fecc8ab2 100644 --- a/bin/oay/Cargo.toml +++ b/bin/oay/Cargo.toml @@ -46,7 +46,7 @@ chrono = "0.4.31" dav-server = { version = "0.7", optional = true } dav-server-opendalfs = { version = "0.3.0", path = "../../integrations/dav-server", optional = true } futures-util = { version = "0.3.29", optional = true } -log = { version = "0.4.22" } +log = { version = "0.4.25" } logforth = { version = "0.21.0", default-features = false } opendal = { version = "0.51.2", path = "../../core", features = [ "services-fs", diff --git a/bin/ofs/Cargo.lock b/bin/ofs/Cargo.lock index e0efe890c100..0ef381431c30 100644 --- a/bin/ofs/Cargo.lock +++ b/bin/ofs/Cargo.lock @@ -335,7 +335,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] @@ -640,10 +640,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1102,7 +1114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1194,7 +1206,7 @@ dependencies = [ "crc32c", "dotenvy", "futures", - "getrandom", + "getrandom 0.2.15", "http", "log", "md-5", @@ -1329,7 +1341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom", + "getrandom 0.2.15", "rand", "ring", "rustc-hash", @@ -1392,7 +1404,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -1435,7 +1447,7 @@ dependencies = [ "base64", "chrono", "form_urlencoded", - "getrandom", + "getrandom 0.2.15", "hex", "hmac", "home", @@ -1505,7 +1517,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -1793,13 +1805,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2095,7 +2107,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", "serde", ] @@ -2130,6 +2142,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.99" @@ -2438,6 +2459,15 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index 83684b5eaa80..d54de8283e82 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -61,6 +61,6 @@ services-s3 = ["opendal/services-s3"] [dev-dependencies] opendal = { version = "0.51.2", path = "../../core", features = ["tests"] } -tempfile = "3.10.1" +tempfile = "3.16.0" test-context = "0.3.0" walkdir = "2.5.0" diff --git a/bin/oli/Cargo.lock b/bin/oli/Cargo.lock index 8e15f3688e06..24031025116a 100644 --- a/bin/oli/Cargo.lock +++ b/bin/oli/Cargo.lock @@ -2397,9 +2397,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom", "serde", diff --git a/bin/oli/Cargo.toml b/bin/oli/Cargo.toml index 063720aa8b1c..50bfb164a3b8 100644 --- a/bin/oli/Cargo.toml +++ b/bin/oli/Cargo.toml @@ -60,7 +60,7 @@ serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.42", features = ["full"] } toml = { version = "0.8" } url = { version = "2.5" } -uuid = { version = "1.11" } +uuid = { version = "1.12" } [dev-dependencies] assert_cmd = { version = "2.0" } diff --git a/core/Cargo.lock b/core/Cargo.lock index 31d09c9a8689..0bda2717856c 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -1590,6 +1590,25 @@ dependencies = [ "cipher", ] +[[package]] +name = "cbindgen" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" +dependencies = [ + "clap", + "heck 0.4.1", + "indexmap 2.7.0", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.95", + "tempfile", + "toml", +] + [[package]] name = "cc" version = "1.2.7" @@ -2098,6 +2117,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crc64fast-nvme" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5e2ee08013e3f228d6d2394116c4549a6df77708442c62d887d83f68ef2ee37" +dependencies = [ + "cbindgen", + "crc", +] + [[package]] name = "criterion" version = "0.5.1" @@ -5145,6 +5174,7 @@ dependencies = [ "chrono", "compio", "crc32c", + "crc64fast-nvme", "criterion", "dashmap 6.1.0", "dotenvy", @@ -7364,6 +7394,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -8580,11 +8619,26 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -8593,6 +8647,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.7.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -9047,9 +9103,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom 0.2.15", "serde", diff --git a/core/Cargo.toml b/core/Cargo.toml index 360ab98c5808..0fea4cee32fd 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -192,6 +192,7 @@ services-s3 = [ "reqsign?/services-aws", "reqsign?/reqwest_request", "dep:crc32c", + "dep:crc64fast-nvme", ] services-seafile = [] services-sftp = ["dep:openssh", "dep:openssh-sftp-client", "dep:bb8"] @@ -352,6 +353,7 @@ compio = { version = "0.12.0", optional = true, features = [ ] } # for services-s3 crc32c = { version = "0.6.6", optional = true } +crc64fast-nvme = {version = "1.1.1", optional = true} # for services-nebula-graph rust-nebula = { version = "^0.0.2", optional = true, features = ["graph"] } snowflaked = { version = "1", optional = true, features = ["sync"] } diff --git a/core/src/services/fs/backend.rs b/core/src/services/fs/backend.rs index 1a0afb9c2e86..90aa3020352d 100644 --- a/core/src/services/fs/backend.rs +++ b/core/src/services/fs/backend.rs @@ -187,6 +187,7 @@ impl Access for FsBackend { write_can_empty: true, write_can_append: true, write_can_multi: true, + write_with_if_not_exists: true, create_dir: true, delete: true, @@ -302,7 +303,14 @@ impl Access for FsBackend { }; let mut open_options = tokio::fs::OpenOptions::new(); - open_options.create(true).write(true); + if op.if_not_exists() { + open_options.create_new(true); + } else { + open_options.create(true); + } + + open_options.write(true); + if op.append() { open_options.append(true); } else { @@ -312,7 +320,19 @@ impl Access for FsBackend { let f = open_options .open(tmp_path.as_ref().unwrap_or(&target_path)) .await - .map_err(new_std_io_error)?; + .map_err(|e| { + match e.kind() { + std::io::ErrorKind::AlreadyExists => { + // Map io AlreadyExists to opendal ConditionNotMatch + Error::new( + ErrorKind::ConditionNotMatch, + "The file already exists in the filesystem", + ) + .set_source(e) + } + _ => new_std_io_error(e), + } + })?; let w = FsWriter::new(target_path, tmp_path, f); @@ -470,7 +490,14 @@ impl Access for FsBackend { }; let mut f = std::fs::OpenOptions::new(); - f.create(true).write(true); + + if op.if_not_exists() { + f.create_new(true); + } else { + f.create(true); + } + + f.write(true); if op.append() { f.append(true); @@ -480,7 +507,19 @@ impl Access for FsBackend { let f = f .open(tmp_path.as_ref().unwrap_or(&target_path)) - .map_err(new_std_io_error)?; + .map_err(|e| { + match e.kind() { + std::io::ErrorKind::AlreadyExists => { + // Map io AlreadyExists to opendal ConditionNotMatch + Error::new( + ErrorKind::ConditionNotMatch, + "The file already exists in the filesystem", + ) + .set_source(e) + } + _ => new_std_io_error(e), + } + })?; Ok((RpWrite::new(), FsWriter::new(target_path, tmp_path, f))) } diff --git a/core/src/services/s3/backend.rs b/core/src/services/s3/backend.rs index 9145f22a7c8b..2875a6167508 100644 --- a/core/src/services/s3/backend.rs +++ b/core/src/services/s3/backend.rs @@ -750,6 +750,7 @@ impl Builder for S3Builder { let checksum_algorithm = match self.config.checksum_algorithm.as_deref() { Some("crc32c") => Some(ChecksumAlgorithm::Crc32c), + Some("crc64nvme") => Some(ChecksumAlgorithm::Crc64nvme), None => None, v => { return Err(Error::new( diff --git a/core/src/services/s3/config.rs b/core/src/services/s3/config.rs index 0c40d73f85fd..60717090ec0c 100644 --- a/core/src/services/s3/config.rs +++ b/core/src/services/s3/config.rs @@ -179,6 +179,7 @@ pub struct S3Config { /// /// Available options: /// - "crc32c" + /// - "crc64nvme" pub checksum_algorithm: Option, /// Disable write with if match so that opendal will not send write request with if match headers. /// diff --git a/core/src/services/s3/core.rs b/core/src/services/s3/core.rs index 69cab8f2b93d..ccd700c398c8 100644 --- a/core/src/services/s3/core.rs +++ b/core/src/services/s3/core.rs @@ -267,6 +267,11 @@ impl S3Core { .for_each(|b| crc = crc32c::crc32c_append(crc, &b)); Some(BASE64_STANDARD.encode(crc.to_be_bytes())) } + Some(ChecksumAlgorithm::Crc64nvme) => { + let mut c = crc64fast_nvme::Digest::new(); + body.clone().for_each(|b| c.write(&b)); + Some(BASE64_STANDARD.encode(c.sum64().to_be_bytes())) + } } } pub fn insert_checksum_header( @@ -938,6 +943,8 @@ pub struct CompleteMultipartUploadRequestPart { pub etag: String, #[serde(rename = "ChecksumCRC32C", skip_serializing_if = "Option::is_none")] pub checksum_crc32c: Option, + #[serde(rename = "ChecksumCRC64NVME", skip_serializing_if = "Option::is_none")] + pub checksum_crc64nvme: Option, } /// Request of DeleteObjects. @@ -1046,11 +1053,13 @@ pub struct ListObjectVersionsOutputDeleteMarker { pub enum ChecksumAlgorithm { Crc32c, + Crc64nvme, } impl ChecksumAlgorithm { pub fn to_header_name(&self) -> HeaderName { match self { Self::Crc32c => HeaderName::from_static("x-amz-checksum-crc32c"), + Self::Crc64nvme => HeaderName::from_static("x-amz-checksum-crc64nvme"), } } } @@ -1061,6 +1070,7 @@ impl Display for ChecksumAlgorithm { "{}", match self { Self::Crc32c => "CRC32C", + Self::Crc64nvme => "CRC64NVME", } ) } diff --git a/core/src/services/s3/writer.rs b/core/src/services/s3/writer.rs index e0c7c5084b59..9b7beb3aa8df 100644 --- a/core/src/services/s3/writer.rs +++ b/core/src/services/s3/writer.rs @@ -147,6 +147,13 @@ impl oio::MultipartWrite for S3Writer { part_number: p.part_number, etag: p.etag.clone(), checksum_crc32c: p.checksum.clone(), + ..Default::default() + }, + ChecksumAlgorithm::Crc64nvme => CompleteMultipartUploadRequestPart { + part_number: p.part_number, + etag: p.etag.clone(), + checksum_crc64nvme: p.checksum.clone(), + ..Default::default() }, }, }) diff --git a/integrations/object_store/Cargo.toml b/integrations/object_store/Cargo.toml index d5aa1acabef5..767a2fa53236 100644 --- a/integrations/object_store/Cargo.toml +++ b/integrations/object_store/Cargo.toml @@ -56,7 +56,7 @@ opendal = { version = "0.51.2", path = "../../core", features = [ rand = "0.8.5" tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread"] } anyhow = "1.0.86" -libtest-mimic = "0.7.3" +libtest-mimic = "0.8.1" uuid = "1.11.0" datafusion = "44.0.0" url = "2.5.2" diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 7b1f6906418e..7de64b4e1f72 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -56,7 +56,7 @@ const config = { } const refName = exec( - "git describe --tags --abbrev=0 --match 'v*'", + "git describe --tags --abbrev=0 --match 'v*' --exclude '*rc*'", ).toString(); const version = semver.parse(refName, {}, true); return `${version.major}.${version.minor}.${version.patch}`;