From 6e42e3fdd218857d6f065d35761f493c4edc14de Mon Sep 17 00:00:00 2001 From: Matthew Messinger Date: Wed, 17 Jul 2024 16:05:35 -0400 Subject: [PATCH 1/8] fix: download failure when remote file is missing If the .tar.xz download fails, it will try again with the .tar.gz file. Fixes #1088 --- Cargo.lock | 1 + Cargo.toml | 1 + src/archive/extract.rs | 2 +- src/archive/mod.rs | 55 ++++++++++++++++++++++++-- src/archive/tar.rs | 27 +++++++++++++ src/archive/tar_xz.rs | 22 ----------- src/archive/zip.rs | 9 ++--- src/downloader.rs | 87 ++++++++++++++++++++---------------------- 8 files changed, 127 insertions(+), 77 deletions(-) create mode 100644 src/archive/tar.rs delete mode 100644 src/archive/tar_xz.rs diff --git a/Cargo.lock b/Cargo.lock index 732f48691..7c91ebf2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -672,6 +672,7 @@ dependencies = [ "encoding_rs_io", "env_logger", "etcetera", + "flate2", "http", "indicatif", "indoc", diff --git a/Cargo.toml b/Cargo.toml index 19efcc048..36617dc15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ thiserror = "1.0.61" clap_complete = "4.5.2" anyhow = "1.0.86" indicatif = { version = "0.17.8", features = ["improved_unicode"] } +flate2 = "1.0.30" [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/src/archive/extract.rs b/src/archive/extract.rs index adce5e6d0..ece7a5c37 100644 --- a/src/archive/extract.rs +++ b/src/archive/extract.rs @@ -39,5 +39,5 @@ impl From for Error { } pub trait Extract { - fn extract_into>(self, path: P) -> Result<(), Error>; + fn extract_into(self: Box, path: &Path) -> Result<(), Error>; } diff --git a/src/archive/mod.rs b/src/archive/mod.rs index ac44763b9..4097e21d2 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -1,11 +1,58 @@ pub mod extract; -pub mod tar_xz; +pub mod tar; pub mod zip; -pub use self::extract::{Error, Extract}; +use std::io::Read; +use std::path::Path; +pub use self::extract::{Error, Extract}; #[cfg(unix)] -pub use self::tar_xz::TarXz; +use self::tar::Tar; #[cfg(windows)] -pub use self::zip::Zip; +use self::zip::Zip; + +pub enum Archive { + #[cfg(windows)] + Zip, + #[cfg(unix)] + TarXz, + #[cfg(unix)] + TarGz, +} + +impl Archive { + pub fn extract_archive_into(&self, path: &Path, response: impl Read) -> Result<(), Error> { + let extractor: Box = match self { + #[cfg(windows)] + Self::Zip => Box::new(Zip::new(response)), + #[cfg(unix)] + Self::TarXz => Box::new(Tar::Xz(response)), + #[cfg(unix)] + Self::TarGz => Box::new(Tar::Gz(response)), + }; + extractor.extract_into(path)?; + Ok(()) + } + + pub fn get_file_suffix(&self) -> String { + match self { + #[cfg(windows)] + Self::Zip => "zip", + #[cfg(unix)] + Self::TarXz => "tar.xz", + #[cfg(unix)] + Self::TarGz => "tar.gz", + }.into() + } + + #[cfg(windows)] + pub fn supported() -> Vec { + vec![Self::Zip] + } + + #[cfg(unix)] + pub fn supported() -> Vec { + vec![Self::TarXz, Self::TarGz] + } +} diff --git a/src/archive/tar.rs b/src/archive/tar.rs new file mode 100644 index 000000000..b23317c51 --- /dev/null +++ b/src/archive/tar.rs @@ -0,0 +1,27 @@ +use super::{extract::Error, Extract}; +use std::{io::Read, path::Path}; + +pub enum Tar { + /// Tar archive with XZ compression + Xz(R), + /// Tar archive with Gzip compression + Gz(R), +} + +impl Tar { + fn extract_into_impl>(self, path: P) -> Result<(), Error> { + let stream: Box = match self { + Self::Xz(response) => Box::new(xz2::read::XzDecoder::new(response)), + Self::Gz(response) => Box::new(flate2::read::GzDecoder::new(response)), + }; + let mut tar_archive = tar::Archive::new(stream); + tar_archive.unpack(&path)?; + Ok(()) + } +} + +impl Extract for Tar { + fn extract_into(self: Box, path: &Path) -> Result<(), Error> { + self.extract_into_impl(path) + } +} diff --git a/src/archive/tar_xz.rs b/src/archive/tar_xz.rs deleted file mode 100644 index ae072cbfd..000000000 --- a/src/archive/tar_xz.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::extract::{Error, Extract}; -use std::{io::Read, path::Path}; - -pub struct TarXz { - response: R, -} - -impl TarXz { - #[allow(dead_code)] - pub fn new(response: R) -> Self { - Self { response } - } -} - -impl Extract for TarXz { - fn extract_into>(self, path: P) -> Result<(), Error> { - let xz_stream = xz2::read::XzDecoder::new(self.response); - let mut tar_archive = tar::Archive::new(xz_stream); - tar_archive.unpack(&path)?; - Ok(()) - } -} diff --git a/src/archive/zip.rs b/src/archive/zip.rs index f9bb01e7e..37a69a365 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -18,8 +18,7 @@ impl Zip { } impl Extract for Zip { - fn extract_into>(mut self, path: P) -> Result<(), Error> { - let path = path.as_ref(); + fn extract_into(mut self: Box, path: &Path) -> Result<(), Error> { let mut tmp_zip_file = tempfile().expect("Can't get a temporary file"); debug!("Created a temporary zip file"); @@ -86,11 +85,11 @@ mod tests { #[test_log::test] fn test_zip_extraction() { - let temp_dir = tempfile::tempdir().expect("Can't create a temp directory"); + let temp_dir = &tempfile::tempdir().expect("Can't create a temp directory"); let response = crate::http::get("https://nodejs.org/dist/v12.0.0/node-v12.0.0-win-x64.zip") .expect("Can't make request to Node v12.0.0 zip file"); - Zip::new(response) - .extract_into(&temp_dir) + Box::new(Zip::new(response)) + .extract_into(temp_dir.as_ref()) .expect("Can't unzip files"); let node_file = temp_dir .as_ref() diff --git a/src/downloader.rs b/src/downloader.rs index a020f57e0..edac3da11 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1,12 +1,10 @@ use crate::arch::Arch; -use crate::archive; -use crate::archive::{Error as ExtractError, Extract}; +use crate::archive::{Archive, Error as ExtractError}; use crate::directory_portal::DirectoryPortal; use crate::progress::ResponseProgress; use crate::version::Version; use indicatif::ProgressDrawTarget; use log::debug; -use std::io::Read; use std::path::Path; use std::path::PathBuf; use thiserror::Error; @@ -38,43 +36,36 @@ pub enum Error { } #[cfg(unix)] -fn filename_for_version(version: &Version, arch: &Arch) -> String { +fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { format!( - "node-{node_ver}-{platform}-{arch}.tar.xz", + "node-{node_ver}-{platform}-{arch}.{ext}", node_ver = &version, platform = crate::system_info::platform_name(), arch = arch, + ext = ext ) } #[cfg(windows)] -fn filename_for_version(version: &Version, arch: &Arch) -> String { +fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { format!( - "node-{node_ver}-win-{arch}.zip", + "node-{node_ver}-win-{arch}.{ext}", node_ver = &version, arch = arch, + ext = ext, ) } -fn download_url(base_url: &Url, version: &Version, arch: &Arch) -> Url { +fn download_url(base_url: &Url, version: &Version, arch: &Arch, ext: String) -> Url { Url::parse(&format!( "{}/{}/{}", base_url.as_str().trim_end_matches('/'), version, - filename_for_version(version, arch) + filename_for_version(version, arch, ext) )) .unwrap() } -fn extract_archive_into(path: impl AsRef, response: impl Read) -> Result<(), Error> { - #[cfg(unix)] - let extractor = archive::TarXz::new(response); - #[cfg(windows)] - let extractor = archive::Zip::new(response); - extractor.extract_into(path)?; - Ok(()) -} - /// Install a Node package pub fn install_node_dist>( version: &Version, @@ -98,39 +89,45 @@ pub fn install_node_dist>( let portal = DirectoryPortal::new_in(&temp_installations_dir, installation_dir); - let url = download_url(node_dist_mirror, version, arch); - debug!("Going to call for {}", &url); - let response = crate::http::get(url.as_str())?; + for extract in Archive::supported().iter() { - if response.status() == 404 { - return Err(Error::VersionNotFound { - version: version.clone(), - arch: arch.clone(), - }); - } + let ext = extract.get_file_suffix(); + let url = download_url(node_dist_mirror, version, arch, ext); + debug!("Going to call for {}", &url); + let response = crate::http::get(url.as_str())?; - debug!("Extracting response..."); - if show_progress { - extract_archive_into( - &portal, - ResponseProgress::new(response, ProgressDrawTarget::stderr()), - )?; - } else { - extract_archive_into(&portal, response)?; - } - debug!("Extraction completed"); + if !response.status().is_success() { + continue; + } + + debug!("Extracting response..."); + if show_progress { + extract.extract_archive_into( + portal.as_ref(), + ResponseProgress::new(response, ProgressDrawTarget::stderr()), + )?; + } else { + extract.extract_archive_into(portal.as_ref(), response)?; + } + debug!("Extraction completed"); - let installed_directory = std::fs::read_dir(&portal)? - .next() - .ok_or(Error::TarIsEmpty)??; - let installed_directory = installed_directory.path(); + let installed_directory = std::fs::read_dir(&portal)? + .next() + .ok_or(Error::TarIsEmpty)??; + let installed_directory = installed_directory.path(); - let renamed_installation_dir = portal.join("installation"); - std::fs::rename(installed_directory, renamed_installation_dir)?; + let renamed_installation_dir = portal.join("installation"); + std::fs::rename(installed_directory, renamed_installation_dir)?; - portal.teleport()?; + portal.teleport()?; - Ok(()) + return Ok(()); + } + + return Err(Error::VersionNotFound { + version: version.clone(), + arch: arch.clone(), + }); } #[cfg(test)] From a99507f7e139867cc22dbe0a0c011e67568b6929 Mon Sep 17 00:00:00 2001 From: Matthew Messinger Date: Thu, 18 Jul 2024 09:57:29 -0400 Subject: [PATCH 2/8] Update changeset --- .changeset/giant-falcons-cover.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/giant-falcons-cover.md diff --git a/.changeset/giant-falcons-cover.md b/.changeset/giant-falcons-cover.md new file mode 100644 index 000000000..401357e34 --- /dev/null +++ b/.changeset/giant-falcons-cover.md @@ -0,0 +1,5 @@ +--- +"fnm": patch +--- + +fix: download failure when remote tar.xz file is missing, falling back to tar.gz From 07114c2e12b1ea2f9eafbd147626bd98d4949011 Mon Sep 17 00:00:00 2001 From: Matthew Messinger Date: Thu, 18 Jul 2024 10:01:19 -0400 Subject: [PATCH 3/8] Update changeset --- .changeset/giant-falcons-cover.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/giant-falcons-cover.md b/.changeset/giant-falcons-cover.md index 401357e34..4b3663f2f 100644 --- a/.changeset/giant-falcons-cover.md +++ b/.changeset/giant-falcons-cover.md @@ -2,4 +2,4 @@ "fnm": patch --- -fix: download failure when remote tar.xz file is missing, falling back to tar.gz +When downloading from node-dist, Fallback to .tar.gz download when the .tar.xz download fails From da51918218e034419e57336cd3ff25030afdc752 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 6 Oct 2024 09:27:59 +0300 Subject: [PATCH 4/8] fix clippy warnings and add test --- e2e/old-versions.test.ts | 17 +++++++++++++++++ src/archive/mod.rs | 10 +++++----- src/downloader.rs | 20 +++++++++++--------- tests/proxy-server/index.mjs | 12 ++++++++---- 4 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 e2e/old-versions.test.ts diff --git a/e2e/old-versions.test.ts b/e2e/old-versions.test.ts new file mode 100644 index 000000000..515271c2f --- /dev/null +++ b/e2e/old-versions.test.ts @@ -0,0 +1,17 @@ +import { script } from "./shellcode/script.js" +import { Bash, Fish, PowerShell, WinCmd, Zsh } from "./shellcode/shells.js" +import testNodeVersion from "./shellcode/test-node-version.js" +import describe from "./describe.js" + +for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) { + describe(shell, () => { + test(`download old Node.js 0.10.x`, async () => { + await script(shell) + .then(shell.env({})) + .then(shell.call("fnm", ["install", "v0.10.36"])) + .then(shell.call("fnm", ["use", "v0.10.36"])) + .then(testNodeVersion(shell, "v0.10.36")) + .execute(shell) + }) + }) +} diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 4097e21d2..a02e94381 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -35,7 +35,7 @@ impl Archive { Ok(()) } - pub fn get_file_suffix(&self) -> String { + pub fn file_extension(&self) -> &'static str { match self { #[cfg(windows)] Self::Zip => "zip", @@ -43,16 +43,16 @@ impl Archive { Self::TarXz => "tar.xz", #[cfg(unix)] Self::TarGz => "tar.gz", - }.into() + } } #[cfg(windows)] - pub fn supported() -> Vec { + pub fn supported() -> &'static [Self] { vec![Self::Zip] } #[cfg(unix)] - pub fn supported() -> Vec { - vec![Self::TarXz, Self::TarGz] + pub fn supported() -> &'static [Self] { + &[Self::TarXz, Self::TarGz] } } diff --git a/src/downloader.rs b/src/downloader.rs index edc36b283..aa1b90cfe 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -36,7 +36,7 @@ pub enum Error { } #[cfg(unix)] -fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { +fn filename_for_version(version: &Version, arch: Arch, ext: &str) -> String { format!( "node-{node_ver}-{platform}-{arch}.{ext}", node_ver = &version, @@ -47,7 +47,7 @@ fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { } #[cfg(windows)] -fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { +fn filename_for_version(version: &Version, arch: &Arch, ext: &str) -> String { format!( "node-{node_ver}-win-{arch}.{ext}", node_ver = &version, @@ -56,7 +56,7 @@ fn filename_for_version(version: &Version, arch: &Arch, ext: String) -> String { ) } -fn download_url(base_url: &Url, version: &Version, arch: &Arch, ext: String) -> Url { +fn download_url(base_url: &Url, version: &Version, arch: Arch, ext: &str) -> Url { Url::parse(&format!( "{}/{}/{}", base_url.as_str().trim_end_matches('/'), @@ -89,12 +89,14 @@ pub fn install_node_dist>( let portal = DirectoryPortal::new_in(&temp_installations_dir, installation_dir); - for extract in Archive::supported().iter() { - let ext = extract.get_file_suffix(); + for extract in Archive::supported() { + let ext = extract.file_extension(); let url = download_url(node_dist_mirror, version, arch, ext); debug!("Going to call for {}", &url); let response = crate::http::get(url.as_str())?; + debug!("{response:?}"); + if !response.status().is_success() { continue; } @@ -122,11 +124,11 @@ pub fn install_node_dist>( return Ok(()); } - - return Err(Error::VersionNotFound { + + Err(Error::VersionNotFound { version: version.clone(), - arch: arch.clone(), - }); + arch, + }) } #[cfg(test)] diff --git a/tests/proxy-server/index.mjs b/tests/proxy-server/index.mjs index 5df0391ae..47b88f3d6 100644 --- a/tests/proxy-server/index.mjs +++ b/tests/proxy-server/index.mjs @@ -30,6 +30,7 @@ const download = async ({ pathname, filename, headersFilename }) => { }, ) const headers = Object.fromEntries(response.headers.entries()) + headers.__status__ = String(response.status) const body = await response.arrayBuffer() fs.writeFileSync(headersFilename, JSON.stringify(headers)) fs.writeFileSync(filename, Buffer.from(body)) @@ -46,10 +47,13 @@ export const server = createServer((req, res) => { const filename = path.join(baseDir, hash) + extension const headersFilename = path.join(baseDir, hash) + ".headers.json" try { - const headers = JSON.parse(fs.readFileSync(headersFilename, "utf-8")) + const { __status__ = "200", ...headers } = JSON.parse( + fs.readFileSync(headersFilename, "utf-8"), + ) + const status = parseInt(__status__, 10) const body = fs.createReadStream(filename) console.log(chalk.green.dim(`[proxy] hit: ${pathname} -> ${filename}`)) - res.writeHead(200, headers) + res.writeHead(status, headers) body.pipe(res) } catch { let promise = cache.get(filename) @@ -74,8 +78,8 @@ export const server = createServer((req, res) => { } promise.then( - ({ headers, body }) => { - res.writeHead(200, headers) + ({ headers: { __status__ = "200", ...headers }, body }) => { + res.writeHead(parseInt(__status__, 10), headers) res.end(Buffer.from(body)) }, (err) => { From 2a5f6b343682863ce2d04d7d600195b0d703d811 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 6 Oct 2024 09:28:43 +0300 Subject: [PATCH 5/8] add snapshot --- e2e/__snapshots__/old-versions.test.ts.snap | 42 +++++++++++++++++++++ e2e/old-versions.test.ts | 1 + 2 files changed, 43 insertions(+) create mode 100644 e2e/__snapshots__/old-versions.test.ts.snap diff --git a/e2e/__snapshots__/old-versions.test.ts.snap b/e2e/__snapshots__/old-versions.test.ts.snap new file mode 100644 index 000000000..358343472 --- /dev/null +++ b/e2e/__snapshots__/old-versions.test.ts.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Bash download old Node.js 0.10.x: Bash 1`] = ` +"set -e +eval "$(fnm env)" +fnm install v0.10.36 +fnm use v0.10.36 +if [ "$(node --version)" != "v0.10.36" ]; then + echo "Expected node version to be v0.10.36. Got $(node --version)" + exit 1 +fi" +`; + +exports[`Fish download old Node.js 0.10.x: Fish 1`] = ` +"fnm env | source +fnm install v0.10.36 +fnm use v0.10.36 +set ____test____ (node --version) +if test "$____test____" != "v0.10.36" + echo "Expected node version to be v0.10.36. Got $____test____" + exit 1 +end" +`; + +exports[`PowerShell download old Node.js 0.10.x: PowerShell 1`] = ` +"$ErrorActionPreference = "Stop" +fnm env | Out-String | Invoke-Expression +fnm install v0.10.36 +fnm use v0.10.36 +if ( "$(node --version)" -ne "v0.10.36" ) { echo "Expected node version to be v0.10.36. Got $(node --version)"; exit 1 }" +`; + +exports[`Zsh download old Node.js 0.10.x: Zsh 1`] = ` +"set -e +eval "$(fnm env)" +fnm install v0.10.36 +fnm use v0.10.36 +if [ "$(node --version)" != "v0.10.36" ]; then + echo "Expected node version to be v0.10.36. Got $(node --version)" + exit 1 +fi" +`; diff --git a/e2e/old-versions.test.ts b/e2e/old-versions.test.ts index 515271c2f..9ec353ebf 100644 --- a/e2e/old-versions.test.ts +++ b/e2e/old-versions.test.ts @@ -11,6 +11,7 @@ for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) { .then(shell.call("fnm", ["install", "v0.10.36"])) .then(shell.call("fnm", ["use", "v0.10.36"])) .then(testNodeVersion(shell, "v0.10.36")) + .takeSnapshot(shell) .execute(shell) }) }) From 6c5652b27247daa2d18e792bb57156ded945cc65 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 6 Oct 2024 09:55:29 +0300 Subject: [PATCH 6/8] fix types --- src/archive/mod.rs | 2 +- src/downloader.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/archive/mod.rs b/src/archive/mod.rs index a02e94381..eec4d9f5a 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -48,7 +48,7 @@ impl Archive { #[cfg(windows)] pub fn supported() -> &'static [Self] { - vec![Self::Zip] + &[Self::Zip] } #[cfg(unix)] diff --git a/src/downloader.rs b/src/downloader.rs index aa1b90cfe..6fb6b6c25 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -47,7 +47,7 @@ fn filename_for_version(version: &Version, arch: Arch, ext: &str) -> String { } #[cfg(windows)] -fn filename_for_version(version: &Version, arch: &Arch, ext: &str) -> String { +fn filename_for_version(version: &Version, arch: Arch, ext: &str) -> String { format!( "node-{node_ver}-win-{arch}.{ext}", node_ver = &version, @@ -95,8 +95,6 @@ pub fn install_node_dist>( debug!("Going to call for {}", &url); let response = crate::http::get(url.as_str())?; - debug!("{response:?}"); - if !response.status().is_success() { continue; } From 14769ea458942e12f715e35b3ad4d6d5f7288ff8 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 6 Oct 2024 14:36:21 +0300 Subject: [PATCH 7/8] skip on windows --- e2e/old-versions.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/e2e/old-versions.test.ts b/e2e/old-versions.test.ts index 9ec353ebf..acb0770d6 100644 --- a/e2e/old-versions.test.ts +++ b/e2e/old-versions.test.ts @@ -2,10 +2,16 @@ import { script } from "./shellcode/script.js" import { Bash, Fish, PowerShell, WinCmd, Zsh } from "./shellcode/shells.js" import testNodeVersion from "./shellcode/test-node-version.js" import describe from "./describe.js" +import os from "node:os" for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) { describe(shell, () => { test(`download old Node.js 0.10.x`, async () => { + if (os.platform() === "win32") { + console.warn(`test skipped as 0.10.x isn't prebuilt for windows`) + return + } + await script(shell) .then(shell.env({})) .then(shell.call("fnm", ["install", "v0.10.36"])) From b90d4e927e3a50c2e8c72103492d5b9b2d2aa50d Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 6 Oct 2024 14:48:13 +0300 Subject: [PATCH 8/8] don't have obsolete snapshots --- e2e/old-versions.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/e2e/old-versions.test.ts b/e2e/old-versions.test.ts index acb0770d6..0e726909a 100644 --- a/e2e/old-versions.test.ts +++ b/e2e/old-versions.test.ts @@ -7,18 +7,18 @@ import os from "node:os" for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) { describe(shell, () => { test(`download old Node.js 0.10.x`, async () => { - if (os.platform() === "win32") { - console.warn(`test skipped as 0.10.x isn't prebuilt for windows`) - return - } - - await script(shell) + const testCase = script(shell) .then(shell.env({})) .then(shell.call("fnm", ["install", "v0.10.36"])) .then(shell.call("fnm", ["use", "v0.10.36"])) .then(testNodeVersion(shell, "v0.10.36")) .takeSnapshot(shell) - .execute(shell) + + if (os.platform() === "win32") { + console.warn(`test skipped as 0.10.x isn't prebuilt for windows`) + } else { + await testCase.execute(shell) + } }) }) }