What is the purpose of this rewrite?
Having this many path dereferences makes me nervous... the original implementation had separate forks to handle each directory case. While the original implementation essentially did the same thing (I think), the operations were semantically separated, providing at least a modicum of cover.
nit: for simple error checking, it is more stable to use the if err := i.extractVersion(); err != nil {} syntax, because if you have a line of these otherwise, you will get shadow warnings from the linter, otherwise. It also makes it easier to move them around.
Did this not throw an error for you? You shouldn't be able to name a method on the struct to the same name as a property on the same struct.
Thankfully, we now have https://pkg.go.dev/slices#Contains which can replace this kind of special-purpose helper.
See https://pkg.go.dev/net/url#Values.Add for a less string-manipulatey way of constructing these URLs.
Good improvements; not much more to go
versions are frequently variously indicates, both with and without a v prefix:
- v1.3.4
- 1.3.4
When trying to parse such things, I tend to want to normalize to one or the other. In this...