lex-github 0.2.4 → 0.3.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -3
  3. data/.rubocop.yml +2 -53
  4. data/CHANGELOG.md +55 -0
  5. data/CLAUDE.md +45 -19
  6. data/Gemfile +1 -0
  7. data/README.md +155 -83
  8. data/lex-github.gemspec +2 -0
  9. data/lib/legion/extensions/github/app/actor/token_refresh.rb +68 -0
  10. data/lib/legion/extensions/github/app/actor/webhook_poller.rb +65 -0
  11. data/lib/legion/extensions/github/app/hooks/setup.rb +19 -0
  12. data/lib/legion/extensions/github/app/hooks/webhook.rb +19 -0
  13. data/lib/legion/extensions/github/app/runners/auth.rb +48 -0
  14. data/lib/legion/extensions/github/app/runners/credential_store.rb +46 -0
  15. data/lib/legion/extensions/github/app/runners/installations.rb +56 -0
  16. data/lib/legion/extensions/github/app/runners/manifest.rb +65 -0
  17. data/lib/legion/extensions/github/app/runners/webhooks.rb +118 -0
  18. data/lib/legion/extensions/github/app/transport/exchanges/app.rb +17 -0
  19. data/lib/legion/extensions/github/app/transport/messages/event.rb +18 -0
  20. data/lib/legion/extensions/github/app/transport/queues/auth.rb +18 -0
  21. data/lib/legion/extensions/github/app/transport/queues/webhooks.rb +18 -0
  22. data/lib/legion/extensions/github/cli/app.rb +57 -0
  23. data/lib/legion/extensions/github/cli/auth.rb +99 -0
  24. data/lib/legion/extensions/github/client.rb +24 -0
  25. data/lib/legion/extensions/github/errors.rb +44 -0
  26. data/lib/legion/extensions/github/helpers/browser_auth.rb +106 -0
  27. data/lib/legion/extensions/github/helpers/cache.rb +99 -0
  28. data/lib/legion/extensions/github/helpers/callback_server.rb +89 -0
  29. data/lib/legion/extensions/github/helpers/client.rb +292 -2
  30. data/lib/legion/extensions/github/helpers/scope_registry.rb +91 -0
  31. data/lib/legion/extensions/github/helpers/token_cache.rb +86 -0
  32. data/lib/legion/extensions/github/middleware/credential_fallback.rb +76 -0
  33. data/lib/legion/extensions/github/middleware/rate_limit.rb +40 -0
  34. data/lib/legion/extensions/github/middleware/scope_probe.rb +37 -0
  35. data/lib/legion/extensions/github/oauth/actor/token_refresh.rb +76 -0
  36. data/lib/legion/extensions/github/oauth/hooks/callback.rb +19 -0
  37. data/lib/legion/extensions/github/oauth/runners/auth.rb +111 -0
  38. data/lib/legion/extensions/github/oauth/transport/exchanges/oauth.rb +17 -0
  39. data/lib/legion/extensions/github/oauth/transport/queues/auth.rb +18 -0
  40. data/lib/legion/extensions/github/runners/actions.rb +100 -0
  41. data/lib/legion/extensions/github/runners/branches.rb +8 -6
  42. data/lib/legion/extensions/github/runners/checks.rb +84 -0
  43. data/lib/legion/extensions/github/runners/comments.rb +15 -9
  44. data/lib/legion/extensions/github/runners/commits.rb +13 -8
  45. data/lib/legion/extensions/github/runners/contents.rb +6 -4
  46. data/lib/legion/extensions/github/runners/deployments.rb +76 -0
  47. data/lib/legion/extensions/github/runners/gists.rb +11 -6
  48. data/lib/legion/extensions/github/runners/issues.rb +18 -11
  49. data/lib/legion/extensions/github/runners/labels.rb +18 -11
  50. data/lib/legion/extensions/github/runners/organizations.rb +12 -10
  51. data/lib/legion/extensions/github/runners/pull_requests.rb +26 -16
  52. data/lib/legion/extensions/github/runners/releases.rb +89 -0
  53. data/lib/legion/extensions/github/runners/repositories.rb +19 -12
  54. data/lib/legion/extensions/github/runners/repository_webhooks.rb +76 -0
  55. data/lib/legion/extensions/github/runners/search.rb +13 -10
  56. data/lib/legion/extensions/github/runners/users.rb +14 -10
  57. data/lib/legion/extensions/github/version.rb +1 -1
  58. data/lib/legion/extensions/github.rb +23 -1
  59. metadata +63 -1
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Github
6
+ module OAuth
7
+ module Actor
8
+ class TokenRefresh < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/SelfContainedActorRunnerClass,Legion/Extension/EveryActorRequiresTime
9
+ def use_runner? = false
10
+ def check_subtask? = false
11
+ def generate_task? = false
12
+
13
+ def time
14
+ 3 * 60 * 60
15
+ end
16
+
17
+ # rubocop:disable Legion/Extension/ActorEnabledSideEffects
18
+ def enabled?
19
+ oauth_settings[:client_id] && oauth_settings[:client_secret]
20
+ rescue StandardError => _e
21
+ false
22
+ end
23
+ # rubocop:enable Legion/Extension/ActorEnabledSideEffects
24
+
25
+ def manual
26
+ settings = oauth_settings
27
+ return unless settings[:client_id] && settings[:client_secret]
28
+
29
+ token_entry = fetch_delegated_token
30
+ return unless token_entry&.dig(:refresh_token)
31
+
32
+ auth = Object.new.extend(Legion::Extensions::Github::OAuth::Runners::Auth)
33
+ result = auth.refresh_token(
34
+ client_id: settings[:client_id],
35
+ client_secret: settings[:client_secret],
36
+ refresh_token: token_entry[:refresh_token]
37
+ )
38
+ return unless result.dig(:result, 'access_token')
39
+
40
+ store_delegated_token(result[:result])
41
+ log.info('OAuth::Actor::TokenRefresh: delegated token refreshed')
42
+ rescue StandardError => e
43
+ log.error("OAuth::Actor::TokenRefresh: #{e.message}")
44
+ end
45
+
46
+ private
47
+
48
+ def oauth_settings
49
+ return {} unless defined?(Legion::Settings)
50
+
51
+ Legion::Settings[:github]&.dig(:oauth) || {}
52
+ rescue StandardError => _e
53
+ {}
54
+ end
55
+
56
+ def fetch_delegated_token
57
+ return nil unless defined?(Legion::Crypt)
58
+
59
+ vault_get('github/oauth/delegated/token')
60
+ rescue StandardError => _e
61
+ nil
62
+ end
63
+
64
+ def store_delegated_token(token_data)
65
+ return unless defined?(Legion::Crypt)
66
+
67
+ vault_write('github/oauth/delegated/token', token_data)
68
+ rescue StandardError => e
69
+ log.warn("OAuth::Actor::TokenRefresh#store_delegated_token: #{e.message}")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Github
6
+ module OAuth
7
+ module Hooks
8
+ class Callback < Legion::Extensions::Hooks::Base # rubocop:disable Legion/Extension/HookMissingRunnerClass
9
+ mount '/callback'
10
+
11
+ def self.runner_class
12
+ 'Legion::Extensions::Github::OAuth::Runners::Auth'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'openssl'
5
+ require 'securerandom'
6
+ require 'uri'
7
+ require 'legion/extensions/github/helpers/client'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Github
12
+ module OAuth
13
+ module Runners
14
+ module Auth
15
+ include Legion::Extensions::Github::Helpers::Client
16
+
17
+ def generate_pkce(**)
18
+ verifier = SecureRandom.urlsafe_base64(32)
19
+ challenge = ::Base64.urlsafe_encode64(
20
+ OpenSSL::Digest::SHA256.digest(verifier), padding: false
21
+ )
22
+ { result: { verifier: verifier, challenge: challenge, challenge_method: 'S256' } }
23
+ end
24
+
25
+ def authorize_url(client_id:, redirect_uri:, scope:, state:,
26
+ code_challenge:, code_challenge_method: 'S256', **)
27
+ params = URI.encode_www_form(
28
+ client_id: client_id, redirect_uri: redirect_uri,
29
+ scope: scope, state: state,
30
+ code_challenge: code_challenge,
31
+ code_challenge_method: code_challenge_method
32
+ )
33
+ { result: "https://github.com/login/oauth/authorize?#{params}" }
34
+ end
35
+
36
+ def exchange_code(client_id:, client_secret:, code:, redirect_uri:, code_verifier:, **)
37
+ response = oauth_connection.post('/login/oauth/access_token', {
38
+ client_id: client_id, client_secret: client_secret,
39
+ code: code, redirect_uri: redirect_uri,
40
+ code_verifier: code_verifier
41
+ })
42
+ { result: response.body }
43
+ end
44
+
45
+ def refresh_token(client_id:, client_secret:, refresh_token:, **)
46
+ response = oauth_connection.post('/login/oauth/access_token', {
47
+ client_id: client_id, client_secret: client_secret,
48
+ refresh_token: refresh_token,
49
+ grant_type: 'refresh_token'
50
+ })
51
+ { result: response.body }
52
+ end
53
+
54
+ def request_device_code(client_id:, scope: 'repo', **)
55
+ response = oauth_connection.post('/login/device/code', {
56
+ client_id: client_id, scope: scope
57
+ })
58
+ { result: response.body }
59
+ end
60
+
61
+ def poll_device_code(client_id:, device_code:, interval: 5, timeout: 300, **)
62
+ deadline = Time.now + timeout
63
+ current_interval = interval
64
+
65
+ loop do
66
+ response = oauth_connection.post('/login/oauth/access_token', {
67
+ client_id: client_id,
68
+ device_code: device_code,
69
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
70
+ })
71
+ body = response.body
72
+ return { result: body } if body[:access_token]
73
+
74
+ error_key = body[:error]
75
+ case error_key
76
+ when 'authorization_pending'
77
+ return { error: 'timeout', description: "Device code flow timed out after #{timeout}s" } if Time.now > deadline
78
+
79
+ sleep(current_interval) unless current_interval.zero?
80
+ when 'slow_down'
81
+ current_interval += 5
82
+ sleep(current_interval) unless current_interval.zero?
83
+ else
84
+ return { error: error_key, description: body[:error_description] }
85
+ end
86
+ end
87
+ end
88
+
89
+ def revoke_token(client_id:, client_secret:, access_token:, **)
90
+ conn = oauth_connection(client_id: client_id, client_secret: client_secret)
91
+ response = conn.delete("/applications/#{client_id}/token", { access_token: access_token })
92
+ { result: response.status == 204 }
93
+ end
94
+
95
+ def oauth_connection(client_id: nil, client_secret: nil, **)
96
+ Faraday.new(url: 'https://github.com') do |conn|
97
+ conn.request :json
98
+ conn.response :json, content_type: /\bjson$/
99
+ conn.headers['Accept'] = 'application/json'
100
+ conn.request :authorization, :basic, client_id, client_secret if client_id && client_secret
101
+ end
102
+ end
103
+
104
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
105
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Github
6
+ module OAuth
7
+ module Transport
8
+ module Exchanges
9
+ class Oauth < Legion::Transport::Exchange
10
+ def exchange_name = 'lex.github.oauth'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Github
6
+ module OAuth
7
+ module Transport
8
+ module Queues
9
+ class Auth < Legion::Transport::Queue
10
+ def queue_name = 'lex.github.oauth.runners.auth'
11
+ def queue_options = { auto_delete: false }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/github/helpers/client'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Github
8
+ module Runners
9
+ module Actions
10
+ include Legion::Extensions::Github::Helpers::Client
11
+
12
+ def list_workflows(owner:, repo:, per_page: 30, page: 1, **)
13
+ response = connection(owner: owner, repo: repo, **).get(
14
+ "/repos/#{owner}/#{repo}/actions/workflows", per_page: per_page, page: page
15
+ )
16
+ { result: response.body }
17
+ end
18
+
19
+ def get_workflow(owner:, repo:, workflow_id:, **)
20
+ response = connection(owner: owner, repo: repo, **).get(
21
+ "/repos/#{owner}/#{repo}/actions/workflows/#{workflow_id}"
22
+ )
23
+ { result: response.body }
24
+ end
25
+
26
+ def list_workflow_runs(owner:, repo:, workflow_id:, status: nil, branch: nil,
27
+ per_page: 30, page: 1, **)
28
+ params = { per_page: per_page, page: page, status: status, branch: branch }.compact
29
+ response = connection(owner: owner, repo: repo, **).get(
30
+ "/repos/#{owner}/#{repo}/actions/workflows/#{workflow_id}/runs", params
31
+ )
32
+ { result: response.body }
33
+ end
34
+
35
+ def get_workflow_run(owner:, repo:, run_id:, **)
36
+ response = connection(owner: owner, repo: repo, **).get(
37
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}"
38
+ )
39
+ { result: response.body }
40
+ end
41
+
42
+ def trigger_workflow(owner:, repo:, workflow_id:, ref:, inputs: {}, **)
43
+ payload = { ref: ref, inputs: inputs }
44
+ response = connection(owner: owner, repo: repo, **).post(
45
+ "/repos/#{owner}/#{repo}/actions/workflows/#{workflow_id}/dispatches", payload
46
+ )
47
+ { result: response.status == 204 }
48
+ end
49
+
50
+ def cancel_workflow_run(owner:, repo:, run_id:, **)
51
+ response = connection(owner: owner, repo: repo, **).post(
52
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/cancel"
53
+ )
54
+ { result: [202, 204].include?(response.status) }
55
+ end
56
+
57
+ def rerun_workflow(owner:, repo:, run_id:, **)
58
+ response = connection(owner: owner, repo: repo, **).post(
59
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/rerun"
60
+ )
61
+ { result: [201, 204].include?(response.status) }
62
+ end
63
+
64
+ def rerun_failed_jobs(owner:, repo:, run_id:, **)
65
+ response = connection(owner: owner, repo: repo, **).post(
66
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/rerun-failed-jobs"
67
+ )
68
+ { result: [201, 204].include?(response.status) }
69
+ end
70
+
71
+ def list_workflow_run_jobs(owner:, repo:, run_id:, filter: 'latest', per_page: 30, page: 1, **)
72
+ params = { filter: filter, per_page: per_page, page: page }
73
+ response = connection(owner: owner, repo: repo, **).get(
74
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/jobs", params
75
+ )
76
+ { result: response.body }
77
+ end
78
+
79
+ def download_workflow_run_logs(owner:, repo:, run_id:, **)
80
+ response = connection(owner: owner, repo: repo, **).get(
81
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/logs"
82
+ )
83
+ { result: { status: response.status, headers: response.headers.to_h, body: response.body } }
84
+ end
85
+
86
+ def list_workflow_run_artifacts(owner:, repo:, run_id:, per_page: 30, page: 1, **)
87
+ params = { per_page: per_page, page: page }
88
+ response = connection(owner: owner, repo: repo, **).get(
89
+ "/repos/#{owner}/#{repo}/actions/runs/#{run_id}/artifacts", params
90
+ )
91
+ { result: response.body }
92
+ end
93
+
94
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
95
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/github/helpers/client'
4
+ require 'legion/extensions/github/helpers/cache'
4
5
 
5
6
  module Legion
6
7
  module Extensions
@@ -8,22 +9,23 @@ module Legion
8
9
  module Runners
9
10
  module Branches
10
11
  include Legion::Extensions::Github::Helpers::Client
12
+ include Legion::Extensions::Github::Helpers::Cache
11
13
 
12
14
  def create_branch(owner:, repo:, branch:, from_ref: 'main', **)
13
- ref_response = connection(**).get("/repos/#{owner}/#{repo}/git/ref/heads/#{from_ref}")
15
+ ref_response = connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/git/ref/heads/#{from_ref}")
14
16
  sha = ref_response.body.dig('object', 'sha')
15
17
 
16
- create_response = connection(**).post("/repos/#{owner}/#{repo}/git/refs",
17
- { ref: "refs/heads/#{branch}", sha: sha })
18
+ create_response = connection(owner: owner, repo: repo, **).post("/repos/#{owner}/#{repo}/git/refs",
19
+ { ref: "refs/heads/#{branch}", sha: sha })
18
20
 
19
21
  { success: true, ref: create_response.body['ref'], sha: sha }
20
22
  rescue StandardError => e
21
- log.warn(e.message) if respond_to?(:log, true)
23
+ log.warn(e.message)
22
24
  { success: false, error: e.message }
23
25
  end
24
26
 
25
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
26
- Legion::Extensions::Helpers.const_defined?(:Lex)
27
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
28
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
27
29
  end
28
30
  end
29
31
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/github/helpers/client'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Github
8
+ module Runners
9
+ module Checks
10
+ include Legion::Extensions::Github::Helpers::Client
11
+
12
+ def create_check_run(owner:, repo:, name:, head_sha:, status: nil, # rubocop:disable Metrics/ParameterLists
13
+ conclusion: nil, output: nil, details_url: nil, **)
14
+ payload = { name: name, head_sha: head_sha, status: status,
15
+ conclusion: conclusion, output: output, details_url: details_url }.compact
16
+ response = connection(owner: owner, repo: repo, **).post(
17
+ "/repos/#{owner}/#{repo}/check-runs", payload
18
+ )
19
+ { result: response.body }
20
+ end
21
+
22
+ def update_check_run(owner:, repo:, check_run_id:, **opts)
23
+ payload = opts.slice(:name, :status, :conclusion, :output, :details_url,
24
+ :started_at, :completed_at)
25
+ response = connection(owner: owner, repo: repo, **opts).patch(
26
+ "/repos/#{owner}/#{repo}/check-runs/#{check_run_id}", payload
27
+ )
28
+ { result: response.body }
29
+ end
30
+
31
+ def get_check_run(owner:, repo:, check_run_id:, **)
32
+ response = connection(owner: owner, repo: repo, **).get(
33
+ "/repos/#{owner}/#{repo}/check-runs/#{check_run_id}"
34
+ )
35
+ { result: response.body }
36
+ end
37
+
38
+ def list_check_runs_for_ref(owner:, repo:, ref:, check_name: nil, status: nil,
39
+ per_page: 30, page: 1, **)
40
+ params = { check_name: check_name, status: status,
41
+ per_page: per_page, page: page }.compact
42
+ response = connection(owner: owner, repo: repo, **).get(
43
+ "/repos/#{owner}/#{repo}/commits/#{ref}/check-runs", params
44
+ )
45
+ { result: response.body }
46
+ end
47
+
48
+ def list_check_suites_for_ref(owner:, repo:, ref:, per_page: 30, page: 1, **)
49
+ params = { per_page: per_page, page: page }
50
+ response = connection(owner: owner, repo: repo, **).get(
51
+ "/repos/#{owner}/#{repo}/commits/#{ref}/check-suites", params
52
+ )
53
+ { result: response.body }
54
+ end
55
+
56
+ def get_check_suite(owner:, repo:, check_suite_id:, **)
57
+ response = connection(owner: owner, repo: repo, **).get(
58
+ "/repos/#{owner}/#{repo}/check-suites/#{check_suite_id}"
59
+ )
60
+ { result: response.body }
61
+ end
62
+
63
+ def rerequest_check_suite(owner:, repo:, check_suite_id:, **)
64
+ response = connection(owner: owner, repo: repo, **).post(
65
+ "/repos/#{owner}/#{repo}/check-suites/#{check_suite_id}/rerequest"
66
+ )
67
+ { result: [201, 204].include?(response.status) }
68
+ end
69
+
70
+ def list_check_run_annotations(owner:, repo:, check_run_id:, per_page: 30, page: 1, **)
71
+ params = { per_page: per_page, page: page }
72
+ response = connection(owner: owner, repo: repo, **).get(
73
+ "/repos/#{owner}/#{repo}/check-runs/#{check_run_id}/annotations", params
74
+ )
75
+ { result: response.body }
76
+ end
77
+
78
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
79
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/github/helpers/client'
4
+ require 'legion/extensions/github/helpers/cache'
4
5
 
5
6
  module Legion
6
7
  module Extensions
@@ -8,35 +9,40 @@ module Legion
8
9
  module Runners
9
10
  module Comments
10
11
  include Legion::Extensions::Github::Helpers::Client
12
+ include Legion::Extensions::Github::Helpers::Cache
11
13
 
12
14
  def list_comments(owner:, repo:, issue_number:, per_page: 30, page: 1, **)
13
15
  params = { per_page: per_page, page: page }
14
- response = connection(**).get("/repos/#{owner}/#{repo}/issues/#{issue_number}/comments", params)
15
- { result: response.body }
16
+ { result: cached_get("github:repo:#{owner}/#{repo}:issues:#{issue_number}:comments:#{page}:#{per_page}") do
17
+ connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/issues/#{issue_number}/comments", params).body
18
+ end }
16
19
  end
17
20
 
18
21
  def get_comment(owner:, repo:, comment_id:, **)
19
- response = connection(**).get("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}")
20
- { result: response.body }
22
+ { result: cached_get("github:repo:#{owner}/#{repo}:comments:#{comment_id}") do
23
+ connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}").body
24
+ end }
21
25
  end
22
26
 
23
27
  def create_comment(owner:, repo:, issue_number:, body:, **)
24
- response = connection(**).post("/repos/#{owner}/#{repo}/issues/#{issue_number}/comments", { body: body })
28
+ response = connection(owner: owner, repo: repo, **).post("/repos/#{owner}/#{repo}/issues/#{issue_number}/comments", { body: body })
25
29
  { result: response.body }
26
30
  end
27
31
 
28
32
  def update_comment(owner:, repo:, comment_id:, body:, **)
29
- response = connection(**).patch("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}", { body: body })
33
+ response = connection(owner: owner, repo: repo, **).patch("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}", { body: body })
34
+ cache_write("github:repo:#{owner}/#{repo}:comments:#{comment_id}", response.body) if response.body['id']
30
35
  { result: response.body }
31
36
  end
32
37
 
33
38
  def delete_comment(owner:, repo:, comment_id:, **)
34
- response = connection(**).delete("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}")
39
+ response = connection(owner: owner, repo: repo, **).delete("/repos/#{owner}/#{repo}/issues/comments/#{comment_id}")
40
+ cache_invalidate("github:repo:#{owner}/#{repo}:comments:#{comment_id}") if response.status == 204
35
41
  { result: response.status == 204 }
36
42
  end
37
43
 
38
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
39
- Legion::Extensions::Helpers.const_defined?(:Lex)
44
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
45
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
40
46
  end
41
47
  end
42
48
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/github/helpers/client'
4
+ require 'legion/extensions/github/helpers/cache'
4
5
 
5
6
  module Legion
6
7
  module Extensions
@@ -8,27 +9,31 @@ module Legion
8
9
  module Runners
9
10
  module Commits
10
11
  include Legion::Extensions::Github::Helpers::Client
12
+ include Legion::Extensions::Github::Helpers::Cache
11
13
 
12
14
  def list_commits(owner:, repo:, sha: nil, per_page: 30, page: 1, **)
13
15
  params = { per_page: per_page, page: page }
14
16
  params[:sha] = sha if sha
15
- response = connection(**).get("/repos/#{owner}/#{repo}/commits", params)
16
- { result: response.body }
17
+ { result: cached_get("github:repo:#{owner}/#{repo}:commits:#{sha}:#{page}:#{per_page}") do
18
+ connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/commits", params).body
19
+ end }
17
20
  end
18
21
 
19
22
  def get_commit(owner:, repo:, ref:, **)
20
- response = connection(**).get("/repos/#{owner}/#{repo}/commits/#{ref}")
21
- { result: response.body }
23
+ { result: cached_get("github:repo:#{owner}/#{repo}:commits:#{ref}") do
24
+ connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/commits/#{ref}").body
25
+ end }
22
26
  end
23
27
 
24
28
  def compare_commits(owner:, repo:, base:, head:, per_page: 30, page: 1, **)
25
29
  params = { per_page: per_page, page: page }
26
- response = connection(**).get("/repos/#{owner}/#{repo}/compare/#{base}...#{head}", params)
27
- { result: response.body }
30
+ { result: cached_get("github:repo:#{owner}/#{repo}:commits:compare:#{base}...#{head}:#{page}:#{per_page}") do
31
+ connection(owner: owner, repo: repo, **).get("/repos/#{owner}/#{repo}/compare/#{base}...#{head}", params).body
32
+ end }
28
33
  end
29
34
 
30
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
31
- Legion::Extensions::Helpers.const_defined?(:Lex)
35
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
36
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
32
37
  end
33
38
  end
34
39
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/github/helpers/client'
4
+ require 'legion/extensions/github/helpers/cache'
4
5
 
5
6
  module Legion
6
7
  module Extensions
@@ -8,9 +9,10 @@ module Legion
8
9
  module Runners
9
10
  module Contents
10
11
  include Legion::Extensions::Github::Helpers::Client
12
+ include Legion::Extensions::Github::Helpers::Cache
11
13
 
12
14
  def commit_files(owner:, repo:, branch:, files:, message:, **)
13
- conn = connection(**)
15
+ conn = connection(owner: owner, repo: repo, **)
14
16
 
15
17
  ref = conn.get("/repos/#{owner}/#{repo}/git/ref/heads/#{branch}")
16
18
  commit_sha = ref.body.dig('object', 'sha')
@@ -33,12 +35,12 @@ module Legion
33
35
 
34
36
  { success: true, commit_sha: new_commit.body['sha'], tree_sha: new_tree.body['sha'] }
35
37
  rescue StandardError => e
36
- log.warn(e.message) if respond_to?(:log, true)
38
+ log.warn(e.message)
37
39
  { success: false, error: e.message }
38
40
  end
39
41
 
40
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
41
- Legion::Extensions::Helpers.const_defined?(:Lex)
42
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
43
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
42
44
  end
43
45
  end
44
46
  end