Skip to content

Commit 92568eb

Browse files
committed
first draft of bot
1 parent 99ea0c2 commit 92568eb

20 files changed

+3058
-0
lines changed

dev/archery/archery/bot.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
import shlex
2+
from functools import partial
3+
4+
import click
5+
import github
6+
7+
8+
class EventError(Exception):
9+
pass
10+
11+
12+
class CommandError(Exception):
13+
14+
def __init__(self, message):
15+
self.message = message
16+
17+
18+
class _CommandMixin:
19+
20+
def get_help_option(self, ctx):
21+
def show_help(ctx, param, value):
22+
if value and not ctx.resilient_parsing:
23+
raise click.UsageError(ctx.get_help())
24+
option = super().get_help_option(ctx)
25+
option.callback = show_help
26+
return option
27+
28+
def __call__(self, message, **kwargs):
29+
args = shlex.split(message)
30+
try:
31+
with self.make_context(self.name, args=args, obj=kwargs) as ctx:
32+
return self.invoke(ctx)
33+
except click.ClickException as e:
34+
raise CommandError(e.format_message())
35+
36+
37+
class Command(_CommandMixin, click.Command):
38+
pass
39+
40+
41+
class Group(_CommandMixin, click.Group):
42+
43+
def command(self, *args, **kwargs):
44+
kwargs.setdefault('cls', Command)
45+
return super().command(*args, **kwargs)
46+
47+
def group(self, *args, **kwargs):
48+
kwargs.setdefault('cls', Group)
49+
return super().group(*args, **kwargs)
50+
51+
def parse_args(self, ctx, args):
52+
if not args and self.no_args_is_help and not ctx.resilient_parsing:
53+
raise click.UsageError(ctx.get_help())
54+
return super().parse_args(ctx, args)
55+
56+
57+
class CommentBot:
58+
59+
def __init__(self, name, handler, token=None):
60+
# TODO(kszucs): validate
61+
self.name = name
62+
self.handler = handler
63+
self.github = github.Github(token)
64+
65+
def parse_command(self, payload):
66+
# only allow users of apache org to submit commands, for more see
67+
# https://developer.github.com/v4/enum/commentauthorassociation/
68+
allowed_roles = {'OWNER', 'MEMBER', 'CONTRIBUTOR'}
69+
mention = f'@{self.name}'
70+
comment = payload['comment']
71+
72+
if payload['sender']['login'] == self.name:
73+
raise EventError("Don't respond to itself")
74+
elif payload['action'] not in {'created', 'edited'}:
75+
raise EventError("Don't respond to comment deletion")
76+
elif comment['author_association'] not in allowed_roles:
77+
raise EventError(
78+
"Don't respond to comments from non-authorized users"
79+
)
80+
elif not comment['body'].lstrip().startswith(mention):
81+
raise EventError("The bot is not mentioned")
82+
83+
return payload['comment']['body'].split(mention)[-1].strip()
84+
85+
def handle(self, event, payload):
86+
try:
87+
command = self.parse_command(payload)
88+
except EventError:
89+
# see the possible reasons in the validate method
90+
return
91+
92+
if event == 'issue_comment':
93+
return self.handle_issue_comment(command, payload)
94+
elif event == 'pull_request_review_comment':
95+
return self.handle_review_comment(command, payload)
96+
else:
97+
raise ValueError("Unexpected event type {}".format(event))
98+
99+
def handle_issue_comment(self, command, payload):
100+
repo = self.github.get_repo(payload['repository']['id'], lazy=True)
101+
issue = repo.get_issue(payload['issue']['number'])
102+
103+
try:
104+
pull = issue.as_pull_request()
105+
except github.GithubException:
106+
return issue.create_comment(
107+
"The comment bot only listens to pull request comments!"
108+
)
109+
110+
comment = pull.get_issue_comment(payload['comment']['id'])
111+
try:
112+
self.handler(command, issue=issue, pull=pull, comment=comment)
113+
except CommandError as e:
114+
pull.create_issue_comment("```\n{}\n```".format(e.message))
115+
except Exception:
116+
comment.create_reaction('-1')
117+
else:
118+
comment.create_reaction('+1')
119+
120+
def handle_review_comment(self, payload):
121+
raise NotImplementedError()
122+
123+
124+
command = partial(click.command, cls=Command)
125+
group = partial(click.group, cls=Group)
126+
127+
128+
@group(name='@ursabot')
129+
@click.pass_context
130+
def bot(ctx):
131+
"""Ursabot"""
132+
ctx.ensure_object(dict)
133+
134+
135+
# @ursabot.command()
136+
# @click.argument('baseline', type=str, metavar='[<baseline>]', default=None,
137+
# required=False)
138+
# @click.option('--suite-filter', metavar='<regex>', show_default=True,
139+
# type=str, default=None, help='Regex filtering benchmark suites.')
140+
# @click.option('--benchmark-filter', metavar='<regex>', show_default=True,
141+
# type=str, default=None,
142+
# help='Regex filtering benchmarks.')
143+
# def benchmark(baseline, suite_filter, benchmark_filter):
144+
# """Run the benchmark suite in comparison mode.
145+
146+
# This command will run the benchmark suite for tip of the branch commit
147+
# against `<baseline>` (or master if not provided).
148+
149+
# Examples:
150+
151+
# \b
152+
# # Run the all the benchmarks
153+
# @ursabot benchmark
154+
155+
# \b
156+
# # Compare only benchmarks where the name matches the /^Sum/ regex
157+
# @ursabot benchmark --benchmark-filter=^Sum
158+
159+
# \b
160+
# # Compare only benchmarks where the suite matches the /compute-/ regex.
161+
# # A suite is the C++ binary.
162+
# @ursabot benchmark --suite-filter=compute-
163+
164+
# \b
165+
# # Sometimes a new optimization requires the addition of new benchmarks to
166+
# # quantify the performance increase. When doing this be sure to add the
167+
# # benchmark in a separate commit before introducing the optimization.
168+
# #
169+
# # Note that specifying the baseline is the only way to compare using a new
170+
# # benchmark, since master does not contain the new benchmark and no
171+
# # comparison is possible.
172+
# #
173+
# # The following command compares the results of matching benchmarks,
174+
# # compiling against HEAD and the provided baseline commit, e.g. eaf8302.
175+
# # You can use this to quantify the performance improvement of new
176+
# # optimizations or to check for regressions.
177+
# @ursabot benchmark --benchmark-filter=MyBenchmark eaf8302
178+
# """
179+
# # each command must return a dictionary which are set as build properties
180+
# props = {'command': 'benchmark'}
181+
182+
# if baseline:
183+
# props['benchmark_baseline'] = baseline
184+
185+
# opts = []
186+
# if suite_filter:
187+
# suite_filter = shlex.quote(suite_filter)
188+
# opts.append(f'--suite-filter={suite_filter}')
189+
# if benchmark_filter:
190+
# benchmark_filter = shlex.quote(benchmark_filter)
191+
# opts.append(f'--benchmark-filter={benchmark_filter}')
192+
193+
# if opts:
194+
# props['benchmark_options'] = opts
195+
196+
# return props
197+
198+
199+
@bot.group()
200+
@click.option('--repo', '-r', default='ursa-labs/crossbow',
201+
help='Crossbow repository on github to use')
202+
@click.pass_obj
203+
def crossbow(props, repo):
204+
"""Trigger crossbow builds for this pull request"""
205+
# TODO(kszucs): validate the repo format
206+
props['command'] = 'crossbow'
207+
props['crossbow_repo'] = repo # github user/repo
208+
props['crossbow_repository'] = f'https://github.com/{repo}' # git url
209+
210+
211+
@crossbow.command()
212+
@click.argument('task', nargs=-1, required=False)
213+
@click.option('--group', '-g', multiple=True,
214+
help='Submit task groups as defined in tests.yml')
215+
@click.pass_obj
216+
def submit(props, task, group):
217+
"""Submit crossbow testing tasks.
218+
219+
See groups defined in arrow/dev/tasks/tests.yml
220+
"""
221+
args = ['-c', 'tasks.yml']
222+
for g in group:
223+
args.extend(['-g', g])
224+
for t in task:
225+
args.append(t)
226+
227+
return {'crossbow_args': args, **props}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{"benchmark": "RegressionSumKernel/32768/10", "change": 0.0046756468886368545, "regression": false, "baseline": 13265442258.099466, "contender": 13327466781.91994, "unit": "bytes_per_second", "less_is_better": false, "suite": "arrow-compute-aggregate-benchmark"}
2+
{"benchmark": "RegressionSumKernel/32768/1", "change": 0.0025108399115900733, "regression": false, "baseline": 15181891659.539782, "contender": 15220010959.05199, "unit": "bytes_per_second", "less_is_better": false, "suite": "arrow-compute-aggregate-benchmark"}
3+
4+
{"benchmark": "RegressionSumKernel/32768/50", "change": 0.00346735806287155, "regression": false, "baseline": 11471825667.817123, "contender": 11511602595.042286, "unit": "bytes_per_second", "less_is_better": false, "suite": "arrow-compute-aggregate-benchmark"}
5+
6+
{"benchmark": "RegressionSumKernel/32768/0", "change": 0.010140954727954987, "regression": false, "baseline": 18316987019.994465, "contender": 18502738756.116768, "unit": "bytes_per_second", "less_is_better": false, "suite": "arrow-compute-aggregate-benchmark"}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{"benchmark":"RegressionSumKernel/32768/50","change":-0.001550846227215492,"regression":false,"baseline":19241207435.428757,"contender":19211367281.47045,"unit":"bytes_per_second","less_is_better":false,"suite":"arrow-compute-aggregate-benchmark"}
2+
{"benchmark":"RegressionSumKernel/32768/1","change":0.0020681767923465765,"regression":true,"baseline":24823170673.777943,"contender":24771831968.277977,"unit":"bytes_per_second","less_is_better":false,"suite":"arrow-compute-aggregate-benchmark"}
3+
{"benchmark":"RegressionSumKernel/32768/10","change":0.0033323376378746905,"regression":false,"baseline":21902707565.968014,"contender":21975694782.76145,"unit":"bytes_per_second","less_is_better":false,"suite":"arrow-compute-aggregate-benchmark"}
4+
{"benchmark":"RegressionSumKernel/32768/0","change":-0.004918126090954414,"regression":true,"baseline":27685006611.446762,"contender":27821164964.790764,"unit":"bytes_per_second","less_is_better":false,"suite":"arrow-compute-aggregate-benchmark"}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
!Job
2+
target: !Target
3+
head: f766a1d615dd1b7ee706d05102e579195951a61c
4+
email: unkown
5+
branch: refs/pull/4435/merge
6+
remote: https://github.com/apache/arrow
7+
version: 0.13.0.dev306
8+
no_rc_version: 0.13.0.dev306
9+
tasks:
10+
docker-cpp-cmake32: !Task
11+
ci: circle
12+
platform: linux
13+
template: docker-tests/circle.linux.yml
14+
artifacts: []
15+
params:
16+
commands:
17+
- docker-compose build cpp-cmake32
18+
- docker-compose run cpp-cmake32
19+
branch: ursabot-1-circle-docker-cpp-cmake32
20+
commit: a56b077c8d1b891a7935048e5672bf6fc07599ec
21+
wheel-osx-cp37m: !Task
22+
ci: travis
23+
platform: osx
24+
template: python-wheels/travis.osx.yml
25+
artifacts:
26+
- pyarrow-0.13.0.dev306-cp37-cp37m-macosx_10_6_intel.whl
27+
params:
28+
python_version: 3.7
29+
branch: ursabot-1-travis-wheel-osx-cp37m
30+
commit: a56b077c8d1b891a7935048e5672bf6fc07599ec
31+
wheel-osx-cp36m: !Task
32+
ci: travis
33+
platform: osx
34+
template: python-wheels/travis.osx.yml
35+
artifacts:
36+
- pyarrow-0.13.0.dev306-cp36-cp36m-macosx_10_6_intel.whl
37+
params:
38+
python_version: 3.6
39+
branch: ursabot-1-travis-wheel-osx-cp36m
40+
commit: a56b077c8d1b891a7935048e5672bf6fc07599ec
41+
wheel-win-cp36m: !Task
42+
ci: appveyor
43+
platform: win
44+
template: python-wheels/appveyor.yml
45+
artifacts:
46+
- pyarrow-0.13.0.dev306-cp36-cp36m-win_amd64.whl
47+
params:
48+
python_version: 3.6
49+
branch: ursabot-1-appveyor-wheel-win-cp36m
50+
commit: a56b077c8d1b891a7935048e5672bf6fc07599ec
51+
branch: ursabot-1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Builder1 (#{build_id})]({build_url}) builder {status}
2+
3+
Revision: {revision}
4+
5+
Submitted crossbow builds: [{repo} @ {branch}](https://github.com/{repo}/branches/all?query={branch})
6+
7+
|Task|Status|
8+
|----|------|
9+
|docker-cpp-cmake32|[![CircleCI](https://img.shields.io/circleci/build/github/{repo}/{branch}-circle-docker-cpp-cmake32.svg)](https://circleci.com/gh/{repo}/tree/{branch}-circle-docker-cpp-cmake32)|
10+
|wheel-osx-cp36m|[![TravisCI](https://img.shields.io/travis/{repo}/{branch}-travis-wheel-osx-cp36m.svg)](https://travis-ci.org/{repo}/branches)|
11+
|wheel-osx-cp37m|[![TravisCI](https://img.shields.io/travis/{repo}/{branch}-travis-wheel-osx-cp37m.svg)](https://travis-ci.org/{repo}/branches)|
12+
|wheel-win-cp36m|[![Appveyor](https://img.shields.io/appveyor/ci/{repo}/{branch}-appveyor-wheel-win-cp36m.svg)](https://ci.appveyor.com/project/{repo}/history)|

0 commit comments

Comments
 (0)