|
35 | 35 |
|
36 | 36 | use std::ffi::OsString; |
37 | 37 | use std::path::Path; |
38 | | -use std::process::{Command, Stdio}; |
| 38 | +use std::process::Command; |
39 | 39 |
|
40 | 40 | use crate::vex_e2e_common::{ |
41 | 41 | assert_absent, assert_attested, assert_not_attested, binary, run_vex, statements_for, |
@@ -112,36 +112,52 @@ pub fn skip(suite: &str, why: &str) { |
112 | 112 | /// probed from a neutral temp dir (an ancestor `packageManager` field would |
113 | 113 | /// make corepack refuse) with the suites' cache isolation applied by |
114 | 114 | /// `isolate`. On `false` the caller returns after [`skip`]. |
| 115 | +/// |
| 116 | +/// A failed fetch is retried (after 2 s, then 5 s) before it counts as |
| 117 | +/// unavailable: one DNS blip on a CI host otherwise fails the leg under |
| 118 | +/// [`REQUIRED_ENV`]`=1` and evicts its merge-queue entry (#1671). |
115 | 119 | pub fn require_yarn_classic(suite: &str, isolate: impl Fn(&mut Command)) -> bool { |
116 | 120 | let spec = yarn_classic(); |
117 | 121 | let want = yarn_classic_version(); |
118 | 122 | let probe = tempfile::tempdir().expect("tempdir"); |
119 | | - let mut cmd = Command::new("corepack"); |
120 | | - cmd.args([spec.as_str(), "--version"]) |
121 | | - .current_dir(probe.path()) |
122 | | - .env("COREPACK_ENABLE_DOWNLOAD_PROMPT", "0"); |
123 | | - isolate(&mut cmd); |
124 | | - let got = cmd |
125 | | - .stderr(Stdio::null()) |
126 | | - .output() |
127 | | - .ok() |
128 | | - .filter(|o| o.status.success()) |
129 | | - .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()); |
130 | | - match got { |
131 | | - Some(v) if v == want => true, |
132 | | - Some(v) => { |
| 123 | + let mut last_err = String::new(); |
| 124 | + for (attempt, backoff) in [0, 2, 5].into_iter().enumerate() { |
| 125 | + std::thread::sleep(std::time::Duration::from_secs(backoff)); |
| 126 | + let mut cmd = Command::new("corepack"); |
| 127 | + cmd.args([spec.as_str(), "--version"]) |
| 128 | + .current_dir(probe.path()) |
| 129 | + .env("COREPACK_ENABLE_DOWNLOAD_PROMPT", "0"); |
| 130 | + isolate(&mut cmd); |
| 131 | + let out = match cmd.output() { |
| 132 | + Ok(out) => out, |
| 133 | + Err(e) => { |
| 134 | + // corepack itself is missing: retrying cannot help. |
| 135 | + last_err = format!("cannot run corepack: {e}"); |
| 136 | + break; |
| 137 | + } |
| 138 | + }; |
| 139 | + if out.status.success() { |
| 140 | + let got = String::from_utf8_lossy(&out.stdout).trim().to_string(); |
| 141 | + if got == want { |
| 142 | + return true; |
| 143 | + } |
133 | 144 | // A wrong release is never a skip: the leg would silently test |
134 | 145 | // another yarn. |
135 | | - panic!("{suite}: `corepack {spec} --version` reported {v:?}, expected {want}"); |
136 | | - } |
137 | | - None => { |
138 | | - skip( |
139 | | - suite, |
140 | | - &format!("`corepack {spec}` unavailable (corepack absent or not fetchable)"), |
141 | | - ); |
142 | | - false |
| 146 | + panic!("{suite}: `corepack {spec} --version` reported {got:?}, expected {want}"); |
143 | 147 | } |
| 148 | + last_err = format!( |
| 149 | + "attempt {} exited {}: {}", |
| 150 | + attempt + 1, |
| 151 | + out.status, |
| 152 | + String::from_utf8_lossy(&out.stderr).trim() |
| 153 | + ); |
| 154 | + eprintln!("{suite}: `corepack {spec} --version` failed, {last_err}"); |
144 | 155 | } |
| 156 | + skip( |
| 157 | + suite, |
| 158 | + &format!("`corepack {spec}` unavailable (corepack absent or not fetchable; {last_err})"), |
| 159 | + ); |
| 160 | + false |
145 | 161 | } |
146 | 162 |
|
147 | 163 | // ── manifest-less VEX ───────────────────────────────────────────────── |
|
0 commit comments