diff options
Diffstat (limited to 'lib/gitlab/golang.rb')
-rw-r--r-- | lib/gitlab/golang.rb | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/gitlab/golang.rb b/lib/gitlab/golang.rb new file mode 100644 index 00000000000..f2dc668c482 --- /dev/null +++ b/lib/gitlab/golang.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module Gitlab + module Golang + extend self + + def local_module_prefix + @gitlab_prefix ||= "#{Settings.build_gitlab_go_url}/".freeze + end + + def semver_tag?(tag) + return false if tag.dereferenced_target.nil? + + Packages::SemVer.match?(tag.name, prefixed: true) + end + + def pseudo_version?(version) + return false unless version + + if version.is_a? String + version = parse_semver version + return false unless version + end + + pre = version.prerelease + + # Valid pseudo-versions are: + # vX.0.0-yyyymmddhhmmss-sha1337beef0, when no earlier tagged commit exists for X + # vX.Y.Z-pre.0.yyyymmddhhmmss-sha1337beef0, when most recent prior tag is vX.Y.Z-pre + # vX.Y.(Z+1)-0.yyyymmddhhmmss-sha1337beef0, when most recent prior tag is vX.Y.Z + + if version.minor != 0 || version.patch != 0 + m = /\A(.*\.)?0\./.freeze.match pre + return false unless m + + pre = pre[m[0].length..] + end + + # This pattern is intentionally more forgiving than the patterns + # above. Correctness is verified by #pseudo_version_commit. + /\A\d{14}-\h+\z/.freeze.match? pre + end + + def pseudo_version_commit(project, semver) + # Per Go's implementation of pseudo-versions, a tag should be + # considered a pseudo-version if it matches one of the patterns + # listed in #pseudo_version?, regardless of the content of the + # timestamp or the length of the SHA fragment. However, an error + # should be returned if the timestamp is not correct or if the SHA + # fragment is not exactly 12 characters long. See also Go's + # implementation of: + # + # - [*codeRepo.validatePseudoVersion](https://github.com/golang/go/blob/daf70d6c1688a1ba1699c933b3c3f04d6f2f73d9/src/cmd/go/internal/modfetch/coderepo.go#L530) + # - [Pseudo-version parsing](https://github.com/golang/go/blob/master/src/cmd/go/internal/modfetch/pseudo.go) + # - [Pseudo-version request processing](https://github.com/golang/go/blob/master/src/cmd/go/internal/modfetch/coderepo.go) + + # Go ignores anything before '.' or after the second '-', so we will do the same + timestamp, sha = semver.prerelease.split('-').last 2 + timestamp = timestamp.split('.').last + commit = project.repository.commit_by(oid: sha) + + # Error messages are based on the responses of proxy.golang.org + + # Verify that the SHA fragment references a commit + raise ArgumentError.new 'invalid pseudo-version: unknown commit' unless commit + + # Require the SHA fragment to be 12 characters long + raise ArgumentError.new 'invalid pseudo-version: revision is shorter than canonical' unless sha.length == 12 + + # Require the timestamp to match that of the commit + raise ArgumentError.new 'invalid pseudo-version: does not match version-control timestamp' unless commit.committed_date.strftime('%Y%m%d%H%M%S') == timestamp + + commit + end + + def parse_semver(str) + Packages::SemVer.parse(str, prefixed: true) + end + + def pkg_go_dev_url(name, version = nil) + if version + "https://pkg.go.dev/#{name}@#{version}" + else + "https://pkg.go.dev/#{name}" + end + end + + def package_url(name, version = nil) + return unless UrlSanitizer.valid?("https://#{name}") + + return pkg_go_dev_url(name, version) unless name.starts_with?(local_module_prefix) + + # This will not work if `name` refers to a subdirectory of a project. This + # could be expanded with logic similar to Gitlab::Middleware::Go to locate + # the project, check for permissions, and return a smarter result. + "#{Gitlab.config.gitlab.protocol}://#{name}/" + end + end +end |