ask-github 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/ask/github/client.rb +91 -11
- data/lib/ask/github/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd64129291b95815da38080f42a150a158ce4f9bfc154b243ad237c209bcd21c
|
|
4
|
+
data.tar.gz: 9a61c3deae1d9e1902e3c8cb379f1c17c44c6c58ddf9bed24fab10ad7da907bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a4e4598c8a7e4924b21d9fb4030c052b2efdb280dcee3c614515e59cf651f896a7320c5fc27d22c9af6509ce3c05c723606c37fe3b3e1a981f19489a8062239
|
|
7
|
+
data.tar.gz: d4d55c62f888a877a31c8b8fcc8523a5e073d5b4ec3f26d12f4936bd3bf3bd373b61bbd0b75aada7842bdbf60a031f8b38e3a1292adca5920a88faa7482f3748
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
- Gemspec validation test. Infrastructure: rubocop, overcommit, bin/setup, CI matrix. VCR rake tasks for cassette freshness.
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
## [0.2.0] - 2026-08-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **client.rb** — `Ask::GitHub.client(token: nil)` accepts an explicit token (the connector path; token resolution still falls back to `Ask::Auth.resolve(:github_token)`).
|
|
12
|
+
- **Content helpers** — `default_branch(repo)`, `tree(repo, branch:)`, `file(repo, path, branch:)`, and `license(repo)` for docs-as-code sources; 401s map to `Ask::Auth::InvalidCredential` like every other call.
|
|
13
|
+
|
|
14
|
+
|
|
7
15
|
## [0.1.2] - 2026-06-21
|
|
8
16
|
|
|
9
17
|
### Added
|
data/lib/ask/github/client.rb
CHANGED
|
@@ -5,27 +5,36 @@ require "ask/auth"
|
|
|
5
5
|
|
|
6
6
|
module Ask
|
|
7
7
|
module GitHub
|
|
8
|
-
# Returns an authenticated Octokit client configured for an AI agent
|
|
8
|
+
# Returns an authenticated Octokit client configured for an AI agent
|
|
9
|
+
# or a content connector.
|
|
9
10
|
#
|
|
10
|
-
# Resolves the GitHub token via +Ask::Auth.resolve(:github_token)
|
|
11
|
-
#
|
|
11
|
+
# Resolves the GitHub token via +Ask::Auth.resolve(:github_token)+,
|
|
12
|
+
# or uses the +token:+ given explicitly (the connector path — the
|
|
13
|
+
# token comes from the host app's own credential store). Configures
|
|
14
|
+
# the client with sensible defaults:
|
|
12
15
|
#
|
|
13
16
|
# - +auto_paginate+: +true+ (collects all pages automatically)
|
|
14
17
|
# - +per_page+: +100+ (maximum items per page)
|
|
15
18
|
# - +middleware+: Faraday retry middleware (3 retries, exponential backoff)
|
|
16
19
|
#
|
|
17
20
|
# The client is wrapped in a +ClientProxy+ that converts
|
|
18
|
-
# +Octokit::Unauthorized+ into +Ask::Auth::InvalidCredential
|
|
21
|
+
# +Octokit::Unauthorized+ into +Ask::Auth::InvalidCredential+, and
|
|
22
|
+
# exposes the repo-content helpers (+default_branch+, +tree+, +file+,
|
|
23
|
+
# +license+) for docs-as-code sources.
|
|
19
24
|
#
|
|
20
25
|
# @example
|
|
21
26
|
# client = Ask::GitHub.client
|
|
22
27
|
# client.issues("owner/repo")
|
|
23
28
|
#
|
|
24
|
-
# @
|
|
29
|
+
# @example connector with an explicit token
|
|
30
|
+
# client = Ask::GitHub.client(token: credential.token)
|
|
31
|
+
# client.default_branch("owner/repo")
|
|
32
|
+
#
|
|
33
|
+
# @return [ClientProxy] an authenticated client
|
|
25
34
|
# @raise [Ask::Auth::MissingCredential] if no GitHub token is configured
|
|
26
35
|
# @raise [Ask::Auth::InvalidCredential] if the token is rejected (401)
|
|
27
|
-
def self.client
|
|
28
|
-
token
|
|
36
|
+
def self.client(token: nil)
|
|
37
|
+
token ||= Ask::Auth.resolve(:github_token)
|
|
29
38
|
|
|
30
39
|
client = Octokit::Client.new(access_token: token, auto_paginate: true, per_page: 100)
|
|
31
40
|
|
|
@@ -39,11 +48,78 @@ module Ask
|
|
|
39
48
|
ClientProxy.new(client)
|
|
40
49
|
end
|
|
41
50
|
|
|
42
|
-
#
|
|
43
|
-
#
|
|
51
|
+
# The repo-content helpers: the raw pieces a docs-as-code connector
|
|
52
|
+
# needs (tree listing, raw file reads, the default branch, and the
|
|
53
|
+
# repo's license). Explicit methods, so connectors never poke at
|
|
54
|
+
# Octokit's full surface.
|
|
55
|
+
class Content
|
|
56
|
+
def initialize(client)
|
|
57
|
+
@client = client
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The repository's default branch name (e.g. "main").
|
|
61
|
+
def default_branch(repo)
|
|
62
|
+
call { @client.repo(repo).default_branch }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The recursive file tree for a branch: [{path:, type:}] entries.
|
|
66
|
+
# GitHub truncates enormous trees; callers bound what they consume.
|
|
67
|
+
def tree(repo, branch: nil)
|
|
68
|
+
sha = branch || default_branch(repo)
|
|
69
|
+
call { @client.tree(repo, sha, recursive: true) }.tree.map do |entry|
|
|
70
|
+
{path: entry.path, type: entry.type}
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# A file's raw content at a path, or nil when the path doesn't exist.
|
|
75
|
+
def file(repo, path, branch: nil)
|
|
76
|
+
call do
|
|
77
|
+
@client.contents(repo, path: path, ref: branch || default_branch(repo),
|
|
78
|
+
accept: "application/vnd.github.raw")
|
|
79
|
+
end
|
|
80
|
+
rescue ::Octokit::NotFound
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The repo's SPDX license id (e.g. "mit"), or nil when unlicensed.
|
|
85
|
+
def license(repo)
|
|
86
|
+
call { @client.license(repo) }&.license&.spdx_id
|
|
87
|
+
rescue ::Octokit::NotFound
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def call
|
|
94
|
+
yield
|
|
95
|
+
rescue ::Octokit::Unauthorized
|
|
96
|
+
::Kernel.raise ::Ask::Auth::InvalidCredential, :github_token
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Proxies method calls to an +Octokit::Client+, converting
|
|
101
|
+
# authentication errors into +Ask::Auth::InvalidCredential+, and
|
|
102
|
+
# exposing the content helpers.
|
|
44
103
|
class ClientProxy < BasicObject
|
|
45
104
|
def initialize(client)
|
|
46
105
|
@client = client
|
|
106
|
+
@content = ::Ask::GitHub::Content.new(client)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def default_branch(repo)
|
|
110
|
+
@content.default_branch(repo)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def tree(repo, branch: nil)
|
|
114
|
+
@content.tree(repo, branch: branch)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def file(repo, path, branch: nil)
|
|
118
|
+
@content.file(repo, path, branch: branch)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def license(repo)
|
|
122
|
+
@content.license(repo)
|
|
47
123
|
end
|
|
48
124
|
|
|
49
125
|
def method_missing(name, ...)
|
|
@@ -52,9 +128,13 @@ module Ask
|
|
|
52
128
|
::Kernel.raise ::Ask::Auth::InvalidCredential, :github_token
|
|
53
129
|
end
|
|
54
130
|
|
|
55
|
-
|
|
56
|
-
|
|
131
|
+
# BasicObject has no +respond_to?+ — report the content helpers
|
|
132
|
+
# explicitly, forward everything else to the wrapped client.
|
|
133
|
+
def respond_to?(name, include_private = false)
|
|
134
|
+
CONTENT_METHODS.include?(name) || @client.respond_to?(name, include_private)
|
|
57
135
|
end
|
|
136
|
+
|
|
137
|
+
CONTENT_METHODS = %i[default_branch tree file license].freeze
|
|
58
138
|
end
|
|
59
139
|
end
|
|
60
140
|
end
|
data/lib/ask/github/version.rb
CHANGED