Checkout tries a failed fetch twice more, after 2 s and 5 s
A fetch from a pull request's fork failed with 'transfer closed with 152 bytes remaining to read', and the check failed with it; the next run's fetch was fine. actions/checkout retries the same way.
1 file+18−20/1 viewed
| 44 | 44 | matches!(process::run(command, Duration::from_secs(600), &mut self.log, &mut commands), Ok(Ended::Exited(0))) | |
| 45 | 45 | } | |
| 46 | 46 | ||
| 47 | + | /// A fetch, tried again after a short wait when it fails: a transfer | |
| 48 | + | /// cut short on the way ("transfer closed with N bytes remaining") is | |
| 49 | + | /// over by the next try. Three tries in all, as actions/checkout does. | |
| 50 | + | fn fetch_retrying(&mut self, dir: &Path, args: &[&str], auth: Option<&str>) -> bool { | |
| 51 | + | for (attempt, wait) in [0u64, 2, 5].into_iter().enumerate() { | |
| 52 | + | if attempt > 0 { | |
| 53 | + | self.log.line(&format!("The fetch failed; trying again in {wait} s ({} of 3).", attempt + 1)); | |
| 54 | + | std::thread::sleep(Duration::from_secs(wait)); | |
| 55 | + | } | |
| 56 | + | if self.git(dir, args, auth) { | |
| 57 | + | return true; | |
| 58 | + | } | |
| 59 | + | } | |
| 60 | + | false | |
| 61 | + | } | |
| 62 | + | ||
| 47 | 63 | /// `actions/checkout`, against g1t. | |
| 48 | 64 | fn checkout(&mut self, with: &BTreeMap<String, String>) -> (bool, BTreeMap<String, String>) { | |
| 49 | 65 | let checkout = self.spec["checkout"].clone(); | |
| 93 | 109 | } | |
| 94 | 110 | args.push("origin"); | |
| 95 | 111 | args.push(&fetch); | |
| 96 | − | if !self.git(&path, &args, auth.as_deref()) { | |
| 112 | + | if !self.fetch_retrying(&path, &args, auth.as_deref()) { | |
| 97 | 113 | self.log.line(&format!("##[error]Could not fetch {fetch} from {repository}.")); | |
| 98 | 114 | return (false, BTreeMap::new()); | |
| 99 | 115 | } | |
| 100 | 116 | let target = sha.clone().unwrap_or_else(|| "FETCH_HEAD".into()); | |
| 101 | 117 | // The commit may be further back than a shallow fetch reaches. | |
| 102 | 118 | let present = Command::new("git").current_dir(&path).args(["cat-file", "-e", &format!("{target}^{{commit}}")]).status().is_ok_and(|s| s.success()); | |
| 103 | − | if !present && !self.git(&path, &["fetch", "--no-tags", "--quiet", "origin"], auth.as_deref()) { | |
| 119 | + | if !present && !self.fetch_retrying(&path, &["fetch", "--no-tags", "--quiet", "origin"], auth.as_deref()) { | |
| 104 | 120 | return (false, BTreeMap::new()); | |
| 105 | 121 | } | |
| 106 | 122 | let checked_out = match &branch { |