Allow partial success in release check#152
Conversation
Introduces the MaybeErrors/NonEmptyErrors/OkMaybe primitives used to accumulate multiple errors instead of bailing on the first one.
Split fetching from parsing and make YAML parsing tolerant of individual bad entries: typed FlatYamlError/RubyLangEntryError plus parse_flat_yaml and ruby_lang_versions, which collect per-entry failures instead of silently dropping them.
call() now returns OkMaybe and threads a MaybeErrors accumulator through fetching, per-version S3 checks, and the output write, so one failure no longer aborts the run. main() reports all accumulated errors and exits non-zero only at the end.
Cover ruby_lang_versions returning valid versions alongside accumulated errors when a single entry fails to parse.
Use !cancelled() so the build-dispatch step still runs when the version check partially fails, and tolerate a missing/empty versions.json, so versions that did resolve still get built while the job stays failed.
cb7f4e5 to
fdfabab
Compare
| /// assert_eq!(maybe.expect("two errors").len().get(), 2); | ||
| /// ``` | ||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| pub struct OkMaybe<T, E>(pub T, pub Option<E>); |
There was a problem hiding this comment.
something about this doesn't sit well with me. can you not achieve a similar result with something like Result<Vec<{enum containing either a RubyDownloadVersion or a non-blocking error}>, Vec<{actual blocking error}>> and get rid of all this extra complexity?
There was a problem hiding this comment.
Thanks for taking a look. I'm trying to avoid some invalid state, such as accidentally returning an error vec that is empty by accident. It's an ergonomic tradeoff, though. This is a continuation of an experiment I've been chewing on for some time.
The simplest replacement for OkMaybe would be just a tuple (T, Option<E>) which...this is mostly just sugar around that. I'm good at saying "this is an experiment," and if it becomes cumbersome or annoying in the future, we can strip back down to just a tuple without too much code change. I'm interested in having Manuel comb through and give some feedback on the type design in the future (but don't want to block on that).
Naming-wise, I'm reaching for "use this as a replacement for Result when you don't want to block generation." So the Ok is trying to evoke feelings of Result while Maybe is literal (an option may or may not be there). We talked about a more direct but verbose naming being FieldWithOption. Another variation with an enum could be ResultAnd where variants are OK(T) and OkAnd(T, E). Though this is maybe a little TOO similar to the familiar Result.
The current Ruby release check scans a document of known Ruby releases and checks our S3 built binaries for missing versions. This preserves behavior but makes some errors non-blocking. For example, if there's a bad or malformed entry in the YAML file, but others are fine, then we can check the good versions while accumulating the bad versions for later inspection.
Overall, the jobs should still be red if any errors are found, which hasn't changed. However, if in that process something succeeds (like a new Ruby version is found) that will be built. Uses patterns I explored in https://schneems.com/2025/03/26/a-daft-procmacro-trick-how-to-emit-partialcode-errors/.
Details in individual commits.