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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3 -3
- data/.rubocop.yml +2 -53
- data/CHANGELOG.md +55 -0
- data/CLAUDE.md +45 -19
- data/Gemfile +1 -0
- data/README.md +155 -83
- data/lex-github.gemspec +2 -0
- data/lib/legion/extensions/github/app/actor/token_refresh.rb +68 -0
- data/lib/legion/extensions/github/app/actor/webhook_poller.rb +65 -0
- data/lib/legion/extensions/github/app/hooks/setup.rb +19 -0
- data/lib/legion/extensions/github/app/hooks/webhook.rb +19 -0
- data/lib/legion/extensions/github/app/runners/auth.rb +48 -0
- data/lib/legion/extensions/github/app/runners/credential_store.rb +46 -0
- data/lib/legion/extensions/github/app/runners/installations.rb +56 -0
- data/lib/legion/extensions/github/app/runners/manifest.rb +65 -0
- data/lib/legion/extensions/github/app/runners/webhooks.rb +118 -0
- data/lib/legion/extensions/github/app/transport/exchanges/app.rb +17 -0
- data/lib/legion/extensions/github/app/transport/messages/event.rb +18 -0
- data/lib/legion/extensions/github/app/transport/queues/auth.rb +18 -0
- data/lib/legion/extensions/github/app/transport/queues/webhooks.rb +18 -0
- data/lib/legion/extensions/github/cli/app.rb +57 -0
- data/lib/legion/extensions/github/cli/auth.rb +99 -0
- data/lib/legion/extensions/github/client.rb +24 -0
- data/lib/legion/extensions/github/errors.rb +44 -0
- data/lib/legion/extensions/github/helpers/browser_auth.rb +106 -0
- data/lib/legion/extensions/github/helpers/cache.rb +99 -0
- data/lib/legion/extensions/github/helpers/callback_server.rb +89 -0
- data/lib/legion/extensions/github/helpers/client.rb +292 -2
- data/lib/legion/extensions/github/helpers/scope_registry.rb +91 -0
- data/lib/legion/extensions/github/helpers/token_cache.rb +86 -0
- data/lib/legion/extensions/github/middleware/credential_fallback.rb +76 -0
- data/lib/legion/extensions/github/middleware/rate_limit.rb +40 -0
- data/lib/legion/extensions/github/middleware/scope_probe.rb +37 -0
- data/lib/legion/extensions/github/oauth/actor/token_refresh.rb +76 -0
- data/lib/legion/extensions/github/oauth/hooks/callback.rb +19 -0
- data/lib/legion/extensions/github/oauth/runners/auth.rb +111 -0
- data/lib/legion/extensions/github/oauth/transport/exchanges/oauth.rb +17 -0
- data/lib/legion/extensions/github/oauth/transport/queues/auth.rb +18 -0
- data/lib/legion/extensions/github/runners/actions.rb +100 -0
- data/lib/legion/extensions/github/runners/branches.rb +8 -6
- data/lib/legion/extensions/github/runners/checks.rb +84 -0
- data/lib/legion/extensions/github/runners/comments.rb +15 -9
- data/lib/legion/extensions/github/runners/commits.rb +13 -8
- data/lib/legion/extensions/github/runners/contents.rb +6 -4
- data/lib/legion/extensions/github/runners/deployments.rb +76 -0
- data/lib/legion/extensions/github/runners/gists.rb +11 -6
- data/lib/legion/extensions/github/runners/issues.rb +18 -11
- data/lib/legion/extensions/github/runners/labels.rb +18 -11
- data/lib/legion/extensions/github/runners/organizations.rb +12 -10
- data/lib/legion/extensions/github/runners/pull_requests.rb +26 -16
- data/lib/legion/extensions/github/runners/releases.rb +89 -0
- data/lib/legion/extensions/github/runners/repositories.rb +19 -12
- data/lib/legion/extensions/github/runners/repository_webhooks.rb +76 -0
- data/lib/legion/extensions/github/runners/search.rb +13 -10
- data/lib/legion/extensions/github/runners/users.rb +14 -10
- data/lib/legion/extensions/github/version.rb +1 -1
- data/lib/legion/extensions/github.rb +23 -1
- 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
|
-
|
|
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)
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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)
|
|
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
|