cc-os/plugins/os-backlog/lib/backlog/tracker.rb

70 lines
2.2 KiB
Ruby
Raw Normal View History

module Backlog
# Validates and classifies tracker keys (the value written to
# `.cc-os/config`'s `tracker` field) and parses `git remote -v` output to
# detect a Forgejo/GitHub remote. Pure — no filesystem, no network.
class Tracker
DEFAULT_FORGEJO_HOST = "forgejo.swansoncloud.com"
FORMATS = {
planka: %r{\Aplanka:[\w.-]+\z},
forgejo: %r{\Aforgejo:[\w.-]+/[\w.-]+\z},
github: %r{\Agithub:[\w.-]+/[\w.-]+\z},
repo: /\Arepo:.+\z/
}.freeze
# @return [Boolean] true if value matches one of the four valid formats
def self.valid?(value)
!kind(value).nil?
end
# @return [Symbol, nil] :planka / :forgejo / :github / :repo, or nil if invalid
def self.kind(value)
return nil unless value.is_a?(String)
FORMATS.each { |name, pattern| return name if value.match?(pattern) }
nil
end
# Parse the first remote line of `git remote -v` output and classify it
# as a Forgejo or GitHub remote (or :unknown for anything else).
#
# @param output [String] raw `git remote -v` output
# @param forgejo_host [String] hostname that identifies the user's
# self-hosted Forgejo instance
# @return [Hash, nil] {kind:, host:, owner:, repo:}, or nil if no remote
# URL could be parsed
def self.parse_remote(output, forgejo_host: DEFAULT_FORGEJO_HOST)
line = output.to_s.lines.first
return nil unless line
url = line.split(/\s+/)[1]
return nil unless url
host, path = split_host_path(url)
return nil unless host && path
owner, repo = path.sub(/\.git\z/, "").split("/").last(2)
return nil unless owner && repo
kind = if host == forgejo_host
:forgejo
elsif host == "github.com"
:github
else
:unknown
end
{ kind: kind, host: host, owner: owner, repo: repo }
end
def self.split_host_path(url)
if url =~ %r{\A[\w+.-]+://(?:[^/@]+@)?([^:/]+)(?::\d+)?/(.+)\z}
[Regexp.last_match(1), Regexp.last_match(2)]
elsif url =~ /\A[^@\s]+@([^:]+):(.+)\z/
[Regexp.last_match(1), Regexp.last_match(2)]
end
end
private_class_method :split_host_path
end
end