Skip to content

Commit c015c4e

Browse files
committed
Add a plugin to poll Gitea pull requests
Based off the existing GithubPulls.pm and GitlabPulls.pm plugins. Also adds an integration test for the new 'giteapulls' input type to the existing 'gitea' test.
1 parent 250668a commit c015c4e

File tree

2 files changed

+143
-14
lines changed

2 files changed

+143
-14
lines changed

nixos-tests.nix

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,18 @@ in
145145
git -C /tmp/repo add .
146146
git config --global user.email test@localhost
147147
git config --global user.name test
148+
149+
# Create initial commit
148150
git -C /tmp/repo commit -m 'Initial import'
149151
git -C /tmp/repo remote add origin gitea@machine:root/repo
150-
GIT_SSH_COMMAND='ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no' \
151-
git -C /tmp/repo push origin master
152+
export GIT_SSH_COMMAND='ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no'
153+
git -C /tmp/repo push origin master
154+
git -C /tmp/repo log >&2
155+
156+
# Create PR branch
157+
git -C /tmp/repo checkout -b pr
158+
git -C /tmp/repo commit --allow-empty -m 'Additional change'
159+
git -C /tmp/repo push origin pr
152160
git -C /tmp/repo log >&2
153161
'';
154162

@@ -185,7 +193,7 @@ in
185193
cat >data.json <<EOF
186194
{
187195
"description": "Trivial",
188-
"checkinterval": "60",
196+
"checkinterval": "20",
189197
"enabled": "1",
190198
"visible": "1",
191199
"keepnr": "1",
@@ -199,7 +207,12 @@ in
199207
"gitea_repo_name": {"value": "repo", "type": "string"},
200208
"gitea_repo_owner": {"value": "root", "type": "string"},
201209
"gitea_status_repo": {"value": "git", "type": "string"},
202-
"gitea_http_url": {"value": "http://localhost:3001", "type": "string"}
210+
"gitea_http_url": {"value": "http://localhost:3001", "type": "string"},
211+
"pulls": {
212+
"type": "giteapulls",
213+
"value": "localhost:3001 root repo http",
214+
"emailresponsible": false
215+
}
203216
}
204217
}
205218
EOF
@@ -227,15 +240,31 @@ in
227240
};
228241

229242
smallDrv = pkgs.writeText "jobset.nix" ''
230-
{ trivial = builtins.derivation {
231-
name = "trivial";
232-
system = "${system}";
233-
builder = "/bin/sh";
234-
allowSubstitutes = false;
235-
preferLocalBuild = true;
236-
args = ["-c" "echo success > $out; exit 0"];
243+
{ pulls, ... }:
244+
245+
let
246+
genDrv = name: builtins.derivation {
247+
inherit name;
248+
system = "${system}";
249+
builder = "/bin/sh";
250+
allowSubstitutes = false;
251+
preferLocalBuild = true;
252+
args = ["-c" "echo success > $out; exit 0"];
237253
};
238-
}
254+
255+
prs = builtins.fromJSON (builtins.readFile pulls);
256+
prJobNames = map (n: "pr-''${n}") (builtins.attrNames prs);
257+
prJobset = builtins.listToAttrs (
258+
map (
259+
name: {
260+
inherit name;
261+
value = genDrv name;
262+
}
263+
) prJobNames
264+
);
265+
in {
266+
trivial = genDrv "trivial";
267+
} // prJobset
239268
'';
240269
in
241270
''
@@ -279,18 +308,34 @@ in
279308
+ '| jq .buildstatus | xargs test 0 -eq'
280309
)
281310
311+
machine.sleep(3)
312+
282313
data = machine.succeed(
283-
'curl -Lf -s "http://localhost:3001/api/v1/repos/root/repo/statuses/$(cd /tmp/repo && git show | head -n1 | awk "{print \\$2}")" '
314+
'curl -Lf -s "http://localhost:3001/api/v1/repos/root/repo/statuses/$(cd /tmp/repo && git show master | head -n1 | awk "{print \\$2}")?sort=leastindex" '
284315
+ "-H 'Accept: application/json' -H 'Content-Type: application/json' "
285316
+ f"-H 'Authorization: token ${api_token}'"
286317
)
287318
288319
response = json.loads(data)
289320
290-
assert len(response) == 2, "Expected exactly three status updates for latest commit (queued, finished)!"
321+
assert len(response) == 2, "Expected exactly two status updates for latest commit (queued, finished)!"
291322
assert response[0]['status'] == "success", "Expected finished status to be success!"
292323
assert response[1]['status'] == "pending", "Expected queued status to be pending!"
293324
325+
# giteapulls test
326+
327+
machine.succeed(
328+
"curl --fail -X POST http://localhost:3001/api/v1/repos/root/repo/pulls "
329+
+ "-H 'Accept: application/json' -H 'Content-Type: application/json' "
330+
+ f"-H 'Authorization: token ${api_token}'"
331+
+ ' -d \'{"title":"Test PR", "base":"master", "head": "pr"}\'''
332+
)
333+
334+
machine.wait_until_succeeds(
335+
'curl -Lf -s http://localhost:3000/build/2 -H "Accept: application/json" '
336+
+ '| jq .buildstatus | xargs test 0 -eq'
337+
)
338+
294339
machine.shutdown()
295340
'';
296341
});

src/lib/Hydra/Plugin/GiteaPulls.pm

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Allow building based on Gitea pull requests.
2+
#
3+
# Example input:
4+
# "pulls": {
5+
# "type": "giteapulls",
6+
# "value": "example.com alice repo"
7+
# "emailresponsible": false
8+
# }
9+
10+
package Hydra::Plugin::GiteaPulls;
11+
12+
use strict;
13+
use warnings;
14+
use parent 'Hydra::Plugin';
15+
use HTTP::Request;
16+
use LWP::UserAgent;
17+
use JSON::MaybeXS;
18+
use Hydra::Helper::CatalystUtils;
19+
use File::Temp;
20+
use POSIX qw(strftime);
21+
22+
sub supportedInputTypes {
23+
my ($self, $inputTypes) = @_;
24+
$inputTypes->{'giteapulls'} = 'Open Gitea Pull Requests';
25+
}
26+
27+
sub _iterate {
28+
my ($url, $auth, $pulls, $ua) = @_;
29+
30+
my $req = HTTP::Request->new('GET', $url);
31+
$req->header('Authorization' => $auth) if defined $auth;
32+
33+
my $res = $ua->request($req);
34+
my $content = $res->decoded_content;
35+
die "Error pulling from the gitea pulls API: $content\n"
36+
unless $res->is_success;
37+
38+
my $pulls_list = decode_json $content;
39+
40+
foreach my $pull (@$pulls_list) {
41+
$pulls->{$pull->{number}} = $pull;
42+
}
43+
44+
# TODO Make Link header parsing more robust!!!
45+
my @links = split ',', ($res->header("Link") // "");
46+
my $next = "";
47+
foreach my $link (@links) {
48+
my ($url, $rel) = split ";", $link;
49+
if (trim($rel) eq 'rel="next"') {
50+
$next = substr trim($url), 1, -1;
51+
last;
52+
}
53+
}
54+
_iterate($next, $auth, $pulls, $ua) unless $next eq "";
55+
}
56+
57+
sub fetchInput {
58+
my ($self, $type, $name, $value, $project, $jobset) = @_;
59+
return undef if $type ne "giteapulls";
60+
61+
my ($baseUrl, $owner, $repo, $proto) = split ' ', $value;
62+
if (not defined $proto) { # the protocol handler is exposed as an option in order to do integration testing
63+
$proto = "https"
64+
}
65+
my $auth = $self->{config}->{gitea_authorization}->{$owner};
66+
67+
my $ua = LWP::UserAgent->new();
68+
my %pulls;
69+
_iterate("$proto://$baseUrl/api/v1/repos/$owner/$repo/pulls?limit=100", $auth, \%pulls, $ua);
70+
71+
my $tempdir = File::Temp->newdir("gitea-pulls" . "XXXXX", TMPDIR => 1);
72+
my $filename = "$tempdir/gitea-pulls.json";
73+
open(my $fh, ">", $filename) or die "Cannot open $filename for writing: $!";
74+
print $fh encode_json \%pulls;
75+
close $fh;
76+
77+
my $storePath = trim(`nix-store --add "$filename"`
78+
or die "cannot copy path $filename to the Nix store.\n");
79+
chomp $storePath;
80+
my $timestamp = time;
81+
return { storePath => $storePath, revision => strftime "%Y%m%d%H%M%S", gmtime($timestamp) };
82+
}
83+
84+
1;

0 commit comments

Comments
 (0)