lex-swarm-github 0.2.0 → 0.2.1
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/lib/legion/extensions/swarm_github/helpers/mesh_integration.rb +61 -0
- data/lib/legion/extensions/swarm_github/runners/pr_pipeline.rb +23 -0
- data/lib/legion/extensions/swarm_github/version.rb +1 -1
- data/lib/legion/extensions/swarm_github.rb +1 -0
- data/spec/legion/extensions/swarm_github/helpers/mesh_integration_spec.rb +155 -0
- data/spec/legion/extensions/swarm_github/runners/pr_pipeline_spec.rb +86 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 51af406fe3fd169d214ad624baa8397ea249af6fd6b2931ce0c16e05476b3089
|
|
4
|
+
data.tar.gz: dff84459e2f0fb6966b1942c271feac122d146d31f44a32a1e3949db3296b7fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 185c32b2089ea81b7d714437c5ea2a468e6e20114831c466466905b548fe499ff1c7734bc6a76cf5fcdad91c279bd56baa0887e5519fdf7c15c58b1c6c5026c4
|
|
7
|
+
data.tar.gz: f17146fded2ba6da1e07e742aaec32f942d2efa8501a66958fbdb00bf15c9c9aa2f308048cd54b1332b7f5009a2e3cf6f20de92d372b3ca53cfa914ee93bb6bb
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module SwarmGithub
|
|
6
|
+
module Helpers
|
|
7
|
+
module MeshIntegration
|
|
8
|
+
AGENT_ID = 'swarm-github-code-reviewer'
|
|
9
|
+
CAPABILITIES = %i[code_review pr_review].freeze
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def register_reviewer
|
|
14
|
+
return { skipped: true, reason: 'lex-mesh not available' } unless mesh_available?
|
|
15
|
+
|
|
16
|
+
Legion::Extensions::Mesh::Client.new.register(
|
|
17
|
+
agent_id: AGENT_ID,
|
|
18
|
+
capabilities: CAPABILITIES,
|
|
19
|
+
endpoint: 'local'
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def record_review_start(charter_id:, owner:, repo:, pull_number:)
|
|
24
|
+
return unless workspace_available?
|
|
25
|
+
|
|
26
|
+
Legion::Extensions::Swarm::Client.new.workspace_put(
|
|
27
|
+
charter_id: charter_id,
|
|
28
|
+
key: "review:#{owner}/#{repo}##{pull_number}",
|
|
29
|
+
value: { status: 'in_progress', started_at: Time.now.utc.to_s },
|
|
30
|
+
author: AGENT_ID
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def record_review_complete(charter_id:, owner:, repo:, pull_number:, result:)
|
|
35
|
+
return unless workspace_available?
|
|
36
|
+
|
|
37
|
+
Legion::Extensions::Swarm::Client.new.workspace_put(
|
|
38
|
+
charter_id: charter_id,
|
|
39
|
+
key: "review:#{owner}/#{repo}##{pull_number}",
|
|
40
|
+
value: {
|
|
41
|
+
status: result[:review]&.dig(:status) || 'unknown',
|
|
42
|
+
posted: result[:post]&.dig(:posted) || false,
|
|
43
|
+
comments_count: result[:post]&.dig(:comments_count) || 0,
|
|
44
|
+
completed_at: Time.now.utc.to_s
|
|
45
|
+
},
|
|
46
|
+
author: AGENT_ID
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def mesh_available?
|
|
51
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def workspace_available?
|
|
55
|
+
defined?(Legion::Extensions::Swarm::Client)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../helpers/mesh_integration'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Extensions
|
|
5
7
|
module SwarmGithub
|
|
@@ -32,6 +34,27 @@ module Legion
|
|
|
32
34
|
run_review_pipeline(owner: owner, repo: repo, pull_number: pull_number,
|
|
33
35
|
slack_channel: slack_channel)
|
|
34
36
|
end
|
|
37
|
+
|
|
38
|
+
def handle_mesh_review_request(payload:, charter_id: nil, **)
|
|
39
|
+
owner = payload[:owner] || payload['owner']
|
|
40
|
+
repo = payload[:repo] || payload['repo']
|
|
41
|
+
pull_number = payload[:pull_number] || payload['pull_number']
|
|
42
|
+
|
|
43
|
+
return { success: false, reason: :missing_params } unless owner && repo && pull_number
|
|
44
|
+
|
|
45
|
+
cid = charter_id || "mesh-review-#{owner}-#{repo}-#{pull_number}"
|
|
46
|
+
Helpers::MeshIntegration.record_review_start(
|
|
47
|
+
charter_id: cid, owner: owner, repo: repo, pull_number: pull_number
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
result = run_review_pipeline(owner: owner, repo: repo, pull_number: pull_number)
|
|
51
|
+
|
|
52
|
+
Helpers::MeshIntegration.record_review_complete(
|
|
53
|
+
charter_id: cid, owner: owner, repo: repo, pull_number: pull_number, result: result
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
result.merge(success: true)
|
|
57
|
+
end
|
|
35
58
|
end
|
|
36
59
|
end
|
|
37
60
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'legion/extensions/swarm_github/version'
|
|
4
4
|
require 'legion/extensions/swarm_github/helpers/pipeline'
|
|
5
5
|
require 'legion/extensions/swarm_github/helpers/issue_tracker'
|
|
6
|
+
require 'legion/extensions/swarm_github/helpers/mesh_integration'
|
|
6
7
|
require 'legion/extensions/swarm_github/runners/github_swarm'
|
|
7
8
|
require 'legion/extensions/swarm_github/runners/pull_request_reviewer'
|
|
8
9
|
require 'legion/extensions/swarm_github/helpers/diff_chunker'
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'legion/extensions/swarm_github/helpers/mesh_integration'
|
|
5
|
+
|
|
6
|
+
RSpec.describe Legion::Extensions::SwarmGithub::Helpers::MeshIntegration do
|
|
7
|
+
subject(:mod) { described_class }
|
|
8
|
+
|
|
9
|
+
describe '.mesh_available?' do
|
|
10
|
+
it 'returns falsy when Mesh::Client is not defined' do
|
|
11
|
+
expect(mod.mesh_available?).to be_falsy
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'returns truthy when Mesh::Client is defined' do
|
|
15
|
+
stub_const('Legion::Extensions::Mesh::Client', Class.new)
|
|
16
|
+
expect(mod.mesh_available?).to be_truthy
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '.workspace_available?' do
|
|
21
|
+
it 'returns falsy when Swarm::Client is not defined' do
|
|
22
|
+
expect(mod.workspace_available?).to be_falsy
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'returns truthy when Swarm::Client is defined' do
|
|
26
|
+
stub_const('Legion::Extensions::Swarm::Client', Class.new)
|
|
27
|
+
expect(mod.workspace_available?).to be_truthy
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '.register_reviewer' do
|
|
32
|
+
context 'when lex-mesh is not available' do
|
|
33
|
+
it 'returns skipped hash' do
|
|
34
|
+
result = mod.register_reviewer
|
|
35
|
+
expect(result[:skipped]).to be true
|
|
36
|
+
expect(result[:reason]).to eq('lex-mesh not available')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'when lex-mesh is available' do
|
|
41
|
+
let(:mesh_client) { instance_double('Legion::Extensions::Mesh::Client') }
|
|
42
|
+
|
|
43
|
+
before do
|
|
44
|
+
stub_const('Legion::Extensions::Mesh::Client', Class.new)
|
|
45
|
+
allow(Legion::Extensions::Mesh::Client).to receive(:new).and_return(mesh_client)
|
|
46
|
+
allow(mesh_client).to receive(:register).and_return({ success: true, registered: true,
|
|
47
|
+
agent_id: described_class::AGENT_ID })
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'calls register on a Mesh::Client instance' do
|
|
51
|
+
expect(mesh_client).to receive(:register).with(
|
|
52
|
+
agent_id: described_class::AGENT_ID,
|
|
53
|
+
capabilities: described_class::CAPABILITIES,
|
|
54
|
+
endpoint: 'local'
|
|
55
|
+
)
|
|
56
|
+
mod.register_reviewer
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns the registration result' do
|
|
60
|
+
result = mod.register_reviewer
|
|
61
|
+
expect(result[:success]).to be true
|
|
62
|
+
expect(result[:registered]).to be true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '.record_review_start' do
|
|
68
|
+
let(:params) { { charter_id: 'cid-1', owner: 'org', repo: 'myrepo', pull_number: 42 } }
|
|
69
|
+
|
|
70
|
+
context 'when lex-swarm is not available' do
|
|
71
|
+
it 'returns nil' do
|
|
72
|
+
expect(mod.record_review_start(**params)).to be_nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'when lex-swarm is available' do
|
|
77
|
+
let(:swarm_client) { instance_double('Legion::Extensions::Swarm::Client') }
|
|
78
|
+
|
|
79
|
+
before do
|
|
80
|
+
stub_const('Legion::Extensions::Swarm::Client', Class.new)
|
|
81
|
+
allow(Legion::Extensions::Swarm::Client).to receive(:new).and_return(swarm_client)
|
|
82
|
+
allow(swarm_client).to receive(:workspace_put).and_return({ success: true })
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'calls workspace_put with in_progress status' do
|
|
86
|
+
expect(swarm_client).to receive(:workspace_put).with(
|
|
87
|
+
charter_id: 'cid-1',
|
|
88
|
+
key: 'review:org/myrepo#42',
|
|
89
|
+
value: hash_including(status: 'in_progress'),
|
|
90
|
+
author: described_class::AGENT_ID
|
|
91
|
+
)
|
|
92
|
+
mod.record_review_start(**params)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'includes started_at timestamp' do
|
|
96
|
+
expect(swarm_client).to receive(:workspace_put).with(
|
|
97
|
+
hash_including(value: hash_including(:started_at))
|
|
98
|
+
)
|
|
99
|
+
mod.record_review_start(**params)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe '.record_review_complete' do
|
|
105
|
+
let(:result) do
|
|
106
|
+
{
|
|
107
|
+
review: { status: 'reviewed' },
|
|
108
|
+
post: { posted: true, comments_count: 3 },
|
|
109
|
+
notify: { notified: true }
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
let(:params) { { charter_id: 'cid-1', owner: 'org', repo: 'myrepo', pull_number: 42, result: result } }
|
|
113
|
+
|
|
114
|
+
context 'when lex-swarm is not available' do
|
|
115
|
+
it 'returns nil' do
|
|
116
|
+
expect(mod.record_review_complete(**params)).to be_nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'when lex-swarm is available' do
|
|
121
|
+
let(:swarm_client) { instance_double('Legion::Extensions::Swarm::Client') }
|
|
122
|
+
|
|
123
|
+
before do
|
|
124
|
+
stub_const('Legion::Extensions::Swarm::Client', Class.new)
|
|
125
|
+
allow(Legion::Extensions::Swarm::Client).to receive(:new).and_return(swarm_client)
|
|
126
|
+
allow(swarm_client).to receive(:workspace_put).and_return({ success: true })
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'calls workspace_put with final status from result' do
|
|
130
|
+
expect(swarm_client).to receive(:workspace_put).with(
|
|
131
|
+
charter_id: 'cid-1',
|
|
132
|
+
key: 'review:org/myrepo#42',
|
|
133
|
+
value: hash_including(status: 'reviewed', posted: true, comments_count: 3),
|
|
134
|
+
author: described_class::AGENT_ID
|
|
135
|
+
)
|
|
136
|
+
mod.record_review_complete(**params)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'includes completed_at timestamp' do
|
|
140
|
+
expect(swarm_client).to receive(:workspace_put).with(
|
|
141
|
+
hash_including(value: hash_including(:completed_at))
|
|
142
|
+
)
|
|
143
|
+
mod.record_review_complete(**params)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'handles missing review status gracefully' do
|
|
147
|
+
result_no_status = { review: nil, post: nil, notify: nil }
|
|
148
|
+
expect(swarm_client).to receive(:workspace_put).with(
|
|
149
|
+
hash_including(value: hash_including(status: 'unknown', posted: false, comments_count: 0))
|
|
150
|
+
)
|
|
151
|
+
mod.record_review_complete(**params, result: result_no_status)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
require 'legion/extensions/swarm_github/helpers/pipeline'
|
|
5
|
+
require 'legion/extensions/swarm_github/helpers/mesh_integration'
|
|
5
6
|
require 'legion/extensions/swarm_github/runners/pull_request_reviewer'
|
|
6
7
|
require 'legion/extensions/swarm_github/runners/review_poster'
|
|
7
8
|
require 'legion/extensions/swarm_github/runners/review_notifier'
|
|
@@ -109,4 +110,89 @@ RSpec.describe Legion::Extensions::SwarmGithub::Runners::PrPipeline do
|
|
|
109
110
|
expect(result[:reason]).to eq('action not reviewable')
|
|
110
111
|
end
|
|
111
112
|
end
|
|
113
|
+
|
|
114
|
+
describe '#handle_mesh_review_request' do
|
|
115
|
+
let(:review_result) do
|
|
116
|
+
{ review: { status: 'reviewed' }, post: { posted: true, comments_count: 2 }, notify: { notified: true } }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
before do
|
|
120
|
+
allow(pipeline).to receive(:run_review_pipeline).and_return(review_result)
|
|
121
|
+
allow(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_start)
|
|
122
|
+
allow(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_complete)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'returns success: false when owner is missing' do
|
|
126
|
+
result = pipeline.handle_mesh_review_request(payload: { repo: 'myrepo', pull_number: 1 })
|
|
127
|
+
expect(result[:success]).to be false
|
|
128
|
+
expect(result[:reason]).to eq(:missing_params)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'returns success: false when repo is missing' do
|
|
132
|
+
result = pipeline.handle_mesh_review_request(payload: { owner: 'org', pull_number: 1 })
|
|
133
|
+
expect(result[:success]).to be false
|
|
134
|
+
expect(result[:reason]).to eq(:missing_params)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'returns success: false when pull_number is missing' do
|
|
138
|
+
result = pipeline.handle_mesh_review_request(payload: { owner: 'org', repo: 'myrepo' })
|
|
139
|
+
expect(result[:success]).to be false
|
|
140
|
+
expect(result[:reason]).to eq(:missing_params)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'calls run_review_pipeline with extracted params' do
|
|
144
|
+
expect(pipeline).to receive(:run_review_pipeline)
|
|
145
|
+
.with(hash_including(owner: 'org', repo: 'myrepo', pull_number: 42))
|
|
146
|
+
.and_return(review_result)
|
|
147
|
+
|
|
148
|
+
pipeline.handle_mesh_review_request(payload: { owner: 'org', repo: 'myrepo', pull_number: 42 })
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it 'merges success: true into pipeline result' do
|
|
152
|
+
result = pipeline.handle_mesh_review_request(
|
|
153
|
+
payload: { owner: 'org', repo: 'myrepo', pull_number: 42 }
|
|
154
|
+
)
|
|
155
|
+
expect(result[:success]).to be true
|
|
156
|
+
expect(result[:review][:status]).to eq('reviewed')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'accepts string-keyed payload' do
|
|
160
|
+
expect(pipeline).to receive(:run_review_pipeline)
|
|
161
|
+
.with(hash_including(owner: 'org', repo: 'myrepo', pull_number: 5))
|
|
162
|
+
.and_return(review_result)
|
|
163
|
+
|
|
164
|
+
pipeline.handle_mesh_review_request(payload: { 'owner' => 'org', 'repo' => 'myrepo', 'pull_number' => 5 })
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'records workspace start before pipeline runs' do
|
|
168
|
+
expect(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_start).ordered
|
|
169
|
+
expect(pipeline).to receive(:run_review_pipeline).ordered.and_return(review_result)
|
|
170
|
+
|
|
171
|
+
pipeline.handle_mesh_review_request(payload: { owner: 'org', repo: 'myrepo', pull_number: 1 })
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'records workspace complete after pipeline runs' do
|
|
175
|
+
expect(pipeline).to receive(:run_review_pipeline).ordered.and_return(review_result)
|
|
176
|
+
expect(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_complete).ordered
|
|
177
|
+
|
|
178
|
+
pipeline.handle_mesh_review_request(payload: { owner: 'org', repo: 'myrepo', pull_number: 1 })
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'uses provided charter_id for workspace calls' do
|
|
182
|
+
expect(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_start)
|
|
183
|
+
.with(hash_including(charter_id: 'my-charter'))
|
|
184
|
+
|
|
185
|
+
pipeline.handle_mesh_review_request(
|
|
186
|
+
payload: { owner: 'org', repo: 'myrepo', pull_number: 1 },
|
|
187
|
+
charter_id: 'my-charter'
|
|
188
|
+
)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it 'generates a charter_id when none provided' do
|
|
192
|
+
expect(Legion::Extensions::SwarmGithub::Helpers::MeshIntegration).to receive(:record_review_start)
|
|
193
|
+
.with(hash_including(charter_id: 'mesh-review-org-myrepo-42'))
|
|
194
|
+
|
|
195
|
+
pipeline.handle_mesh_review_request(payload: { owner: 'org', repo: 'myrepo', pull_number: 42 })
|
|
196
|
+
end
|
|
197
|
+
end
|
|
112
198
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-swarm-github
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -25,6 +25,7 @@ files:
|
|
|
25
25
|
- lib/legion/extensions/swarm_github/client.rb
|
|
26
26
|
- lib/legion/extensions/swarm_github/helpers/diff_chunker.rb
|
|
27
27
|
- lib/legion/extensions/swarm_github/helpers/issue_tracker.rb
|
|
28
|
+
- lib/legion/extensions/swarm_github/helpers/mesh_integration.rb
|
|
28
29
|
- lib/legion/extensions/swarm_github/helpers/pipeline.rb
|
|
29
30
|
- lib/legion/extensions/swarm_github/runners/github_swarm.rb
|
|
30
31
|
- lib/legion/extensions/swarm_github/runners/pr_pipeline.rb
|
|
@@ -37,6 +38,7 @@ files:
|
|
|
37
38
|
- spec/legion/extensions/swarm_github/client_spec.rb
|
|
38
39
|
- spec/legion/extensions/swarm_github/helpers/diff_chunker_spec.rb
|
|
39
40
|
- spec/legion/extensions/swarm_github/helpers/issue_tracker_spec.rb
|
|
41
|
+
- spec/legion/extensions/swarm_github/helpers/mesh_integration_spec.rb
|
|
40
42
|
- spec/legion/extensions/swarm_github/helpers/pipeline_spec.rb
|
|
41
43
|
- spec/legion/extensions/swarm_github/runners/github_swarm_spec.rb
|
|
42
44
|
- spec/legion/extensions/swarm_github/runners/pr_pipeline_spec.rb
|