Fix nil capture handling in coverage extraction
What does this MR do and why?
Gitlab::Ci::Trace::Stream#extract_coverage scans a job log backwards and applies the project's coverage regex to each line. The scan goes through Gitlab::UntrustedRegexp#scan (RE2), which returns one slot per capture group for every match. A group that did not take part in the match — an unused alternation branch, or an optional group — occupies its slot as nil.
The code took the last slot unconditionally, so any regex whose trailing group can go unused handed a nil to gsub:
Gitlab::UntrustedRegexp.new('Coverage: (\d+\.\d+)\%|Total coverage: (\d+)\%').scan('Coverage: 98.29%')
# => [["98.29", nil]]extract_coverage rescues and reports the resulting NoMethodError, so it is no longer a crash, but extraction stops at the first matching line and the job ends up with no coverage at all. Projects whose regex uses alternation therefore never get coverage from their jobs.
This MR takes the last captured value instead, and moves on to the next line when a match captured nothing.