Class: GemContribute::HostAdapters::GitHubAdapter

Inherits:
GemContribute::HostAdapter show all
Defined in:
lib/gem_contribute/host_adapters/github_adapter.rb

Overview

GitHub adapter. v0.1 implements the unauthenticated read methods (issues, community_profile, file_contents). The auth-required methods raise AuthRequired so the calling layer (CLI in Stage 2, TUI in Stage 3) can trigger device flow. See ADR-0001 and ADR-0004.

‘token` is optional and reserved for Stage 2; when present it’s sent as ‘Authorization: Bearer …` to lift the rate limit and unlock fork/etc.

Defined Under Namespace

Classes: RateLimit

Constant Summary collapse

API_BASE =
"https://api.github.com"
ACCEPT =
"application/vnd.github+json"
API_VERSION =
"2022-11-28"
MAX_REDIRECTS =
3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cache: Cache.new, http: Net::HTTP, token: nil) ⇒ GitHubAdapter

Returns a new instance of GitHubAdapter.



26
27
28
29
30
31
32
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 26

def initialize(cache: Cache.new, http: Net::HTTP, token: nil)
  super()
  @cache = cache
  @http = http
  @token = token
  @rate_limit = nil
end

Instance Attribute Details

#rate_limitObject (readonly)

Returns the value of attribute rate_limit.



24
25
26
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 24

def rate_limit
  @rate_limit
end

Instance Method Details

#already_forked?(project) ⇒ Boolean

GET /repos/:viewer/:repo. True iff the viewer already owns a fork of the upstream repo at the same name.

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 93

def already_forked?(project)
  raise AuthRequired, "github.com" unless @token

  ensure_known_host!(project)
  viewer = 
  get_json("/repos/#{viewer}/#{project.repo}")
  true
rescue AdapterError => e
  return false if e.message.include?("404")

  raise
end

#community_profile(project) ⇒ Object



59
60
61
62
63
64
65
66
67
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 59

def community_profile(project)
  ensure_known_host!(project)
  cache_key = "#{project.owner}/#{project.repo}"
  cached = @cache.fetch("repos", cache_key)
  return cached if cached

  body = get_json("/repos/#{project.owner}/#{project.repo}/community/profile")
  @cache.write("repos", cache_key, body)
end

#file_contents(project, path) ⇒ Object



69
70
71
72
73
74
75
76
77
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 69

def file_contents(project, path)
  ensure_known_host!(project)
  cache_key = "#{project.owner}/#{project.repo}:#{path}"
  cached = @cache.fetch("files", cache_key)
  return cached if cached

  body = get_json("/repos/#{project.owner}/#{project.repo}/contents/#{path}")
  @cache.write("files", cache_key, body)
end

#fork(project) ⇒ Object

POST /repos/:owner/:repo/forks. Returns the fork’s parsed body (clone_url, owner.login, name, etc.). GitHub responds 202 (accepted) immediately even if the fork is still propagating; callers that need to clone right after may want to poll readiness — see ‘fork_ready?` below.

Raises:



84
85
86
87
88
89
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 84

def fork(project)
  raise AuthRequired, "github.com" unless @token

  ensure_known_host!(project)
  post_json("/repos/#{project.owner}/#{project.repo}/forks")
end

#fork_ready?(viewer, repo_name) ⇒ Boolean

GET /repos/:viewer/:repo, returning true once GitHub has finished provisioning the fork. The fork endpoint returns 202 immediately; the resource may 404 for a few seconds before becoming live.

Returns:

  • (Boolean)


118
119
120
121
122
123
124
125
126
127
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 118

def fork_ready?(viewer, repo_name)
  raise AuthRequired, "github.com" unless @token

  get_json("/repos/#{viewer}/#{repo_name}")
  true
rescue AdapterError => e
  return false if e.message.include?("404")

  raise
end

#issue(owner, repo, number) ⇒ Hash

Returns a single issue’s full payload (uncached — submit only).

Returns:

  • (Hash)

    a single issue’s full payload (uncached — submit only).



35
36
37
38
39
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 35

def issue(owner, repo, number)
  ensure_known_host!(Project.new(gem_name: repo, host: "github.com",
                                 owner: owner, repo: repo, metadata: {}))
  get_json("/repos/#{owner}/#{repo}/issues/#{number}")
end

#issues(project, labels: nil) ⇒ Array<Hash>

Returns open issues filtered to the given labels (if any).

Returns:

  • (Array<Hash>)

    open issues filtered to the given labels (if any)



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 42

def issues(project, labels: nil)
  ensure_known_host!(project)

  cache_key = issue_cache_key(project, labels)
  cached = @cache.fetch("issues", cache_key)
  return cached if cached

  params = { state: "open", per_page: 50 }
  params[:labels] = Array(labels).join(",") if labels && !Array(labels).empty?
  body = get_json("/repos/#{project.owner}/#{project.repo}/issues", params)

  # GitHub's /issues endpoint mixes pull requests in. PRs have a
  # `pull_request` key; filter those out so callers see issues only.
  only_issues = body.reject { |i| i.key?("pull_request") }
  @cache.write("issues", cache_key, only_issues)
end

#viewer_loginObject

GET /user. Used by ‘auth status` and `already_forked?`. Returns the authenticated user’s login string (e.g. “cdhagmann”).

Raises:



108
109
110
111
112
113
# File 'lib/gem_contribute/host_adapters/github_adapter.rb', line 108

def 
  raise AuthRequired, "github.com" unless @token

  body = get_json("/user")
  body.fetch("login")
end