Skip to content

Commit

Permalink
add gitea support, fixes #3
Browse files Browse the repository at this point in the history
  • Loading branch information
nektro committed Jan 25, 2022
1 parent 1f0c59b commit f212532
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
49 changes: 45 additions & 4 deletions src/db/Remote.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub var all_remotes: []const Remote = &.{};

pub const Type = enum {
github,
gitea,

pub const BaseType = string;
};
Expand Down Expand Up @@ -94,12 +95,25 @@ pub fn listUserRepos(self: Remote, alloc: std.mem.Allocator, user: User) ![]cons
}
}
},
.gitea => blk: {
const endpoint = try std.fmt.allocPrint(alloc, "/repos/search?uid={s}&limit=100&sort=updated&private=false", .{user.snowflake});
const resp = (try self.apiRequest(alloc, user, endpoint)) orelse break :blk;
const val = resp.getT("data", .Array) orelse break :blk;
for (val) |item| {
// NOTE: this filter will not have an effect until Gitea 1.17.0 lands (#18395)
if (std.mem.eql(u8, item.getT("language", .String) orelse "", "Zig")) {
const id = try std.fmt.allocPrint(alloc, "{d}", .{item.getT("id", .Int).?});
const name = item.getT("full_name", .String).?;
try list.append(.{ .id = id, .name = name, .added = containsPackage(pkgs, id) });
}
}
},
}
return list.toOwnedSlice();
}

fn apiRequest(self: Remote, alloc: std.mem.Allocator, user: ?User, endpoint: string) !?json.Value {
const url = try std.mem.concat(alloc, u8, &.{ try self.apiRoot(), endpoint });
const url = try std.mem.concat(alloc, u8, &.{ try self.apiRoot(alloc), endpoint });
defer alloc.free(url);

const req = try zfetch.Request.init(alloc, url, null);
Expand All @@ -110,7 +124,10 @@ fn apiRequest(self: Remote, alloc: std.mem.Allocator, user: ?User, endpoint: str

if (user) |_| {
if (_handler.getAccessToken(try user.?.uuid.toString(alloc))) |token| {
try headers.appendValue("Authorization", try std.mem.join(alloc, " ", &.{ "Bearer", token }));
switch (self.type) {
.github => try headers.appendValue("Authorization", try std.mem.join(alloc, " ", &.{ "Bearer", token })),
.gitea => try headers.appendValue("Authorization", try std.mem.join(alloc, " ", &.{ "token", token })),
}
}
}

Expand All @@ -126,9 +143,10 @@ fn apiRequest(self: Remote, alloc: std.mem.Allocator, user: ?User, endpoint: str
return val;
}

fn apiRoot(self: Remote) error{}!string {
fn apiRoot(self: Remote, alloc: std.mem.Allocator) !string {
return switch (self.type) {
.github => "https://api.github.com",
.gitea => try std.fmt.allocPrint(alloc, "https://{s}/api/v1", .{self.domain}),
};
}

Expand All @@ -140,6 +158,7 @@ pub fn getRepo(self: Remote, alloc: std.mem.Allocator, repo: string) !RepoDetail
null,
try std.mem.join(alloc, "/", switch (self.type) {
.github => &.{ "", "repos", repo },
.gitea => &.{ "", "repos", repo },
}),
)) orelse return error.ApiRequestFail,
);
Expand All @@ -156,6 +175,15 @@ pub fn parseDetails(self: Remote, alloc: std.mem.Allocator, raw: json.Value) !Re
.star_count = @intCast(u32, raw.getT("stargazers_count", .Int).?),
.owner = raw.getT(.{ "owner", "login" }, .String).?,
},
.gitea => .{
.id = try std.fmt.allocPrint(alloc, "{}", .{raw.getT("id", .Int).?}),
.name = raw.getT("name", .String).?,
.clone_url = raw.getT("clone_url", .String).?,
.description = raw.getT("description", .String).?,
.default_branch = raw.getT("default_branch", .String).?,
.star_count = @intCast(u32, raw.getT("stars_count", .Int).?),
.owner = raw.getT(.{ "owner", "login" }, .String).?,
},
};
}

Expand All @@ -165,11 +193,14 @@ pub fn installWebhook(self: Remote, alloc: std.mem.Allocator, user: User, rm_id:
.github => try self.apiPost(alloc, user, try std.mem.concat(alloc, u8, &.{ "/repos/", rm_name, "/hooks" }), GithubWebhookData{
.config = .{ .url = hookurl },
}),
.gitea => try self.apiPost(alloc, user, try std.mem.concat(alloc, u8, &.{ "/repos/", rm_name, "/hooks" }), GiteaCreateHookBody{
.config = .{ .url = hookurl },
}),
};
}

fn apiPost(self: Remote, alloc: std.mem.Allocator, user: ?User, endpoint: string, data: anytype) !?json.Value {
const url = try std.mem.concat(alloc, u8, &.{ try self.apiRoot(), endpoint });
const url = try std.mem.concat(alloc, u8, &.{ try self.apiRoot(alloc), endpoint });
defer alloc.free(url);

const req = try zfetch.Request.init(alloc, url, null);
Expand Down Expand Up @@ -220,3 +251,13 @@ const GithubWebhookData = struct {
active: bool = true,
},
};

const GiteaCreateHookBody = struct {
active: bool = true,
config: struct {
url: string,
content_type: string = "json",
},
events: []const string = &.{"push"},
type: string = "gitea",
};
10 changes: 9 additions & 1 deletion src/handler/hook.zig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ pub fn post(_: void, response: *http.Response, request: http.Request, args: stru
if (std.mem.eql(u8, event_type, "ping")) return try response.writer().writeAll("Pong!\n");
try _internal.assert(std.mem.eql(u8, event_type, "push"), response, .bad_request, "error: unknown webhook event type: {s}", .{event_type});

const ref = val.getT("ref", .String) orelse return _internal.fail(response, .bad_request, "error: webhook json key not found: ref", .{});
const branch = val.getT(.{ "repository", "default_branch" }, .String) orelse return _internal.fail(response, .bad_request, "error: webhook json key not found: repository.default_branch", .{});
try _internal.assert(std.mem.eql(u8, ref, try std.fmt.allocPrint(alloc, "refs/heads/{s}", .{branch})), response, .bad_request, "error: push even was not to default branch: {s}", .{ref});
},
.gitea => {
const event_type = headers.get("X-Gitea-Event") orelse "";
try _internal.assert(std.mem.eql(u8, event_type, "push"), response, .bad_request, "error: unknown webhook event type: {s}", .{event_type});

const ref = val.getT("ref", .String) orelse return _internal.fail(response, .bad_request, "error: webhook json key not found: ref", .{});
const branch = val.getT(.{ "repository", "default_branch" }, .String) orelse return _internal.fail(response, .bad_request, "error: webhook json key not found: repository.default_branch", .{});
try _internal.assert(std.mem.eql(u8, ref, try std.fmt.allocPrint(alloc, "refs/heads/{s}", .{branch})), response, .bad_request, "error: push even was not to default branch: {s}", .{ref});
Expand All @@ -41,11 +49,11 @@ pub fn post(_: void, response: *http.Response, request: http.Request, args: stru

const details: db.Remote.RepoDetails = switch (r.type) {
.github => try r.parseDetails(alloc, val.get("repository") orelse return _internal.fail(response, .internal_server_error, "error: webhook json key not found: repository", .{})),
.gitea => try r.parseDetails(alloc, val.get("repository") orelse return _internal.fail(response, .internal_server_error, "error: webhook json key not found: repository", .{})),
};
try _internal.assert(std.mem.eql(u8, details.owner, u.name), response, .forbidden, "error: you do not have the authority to manage this package", .{});

var path = std.mem.span(cmisc.mkdtemp(try alloc.dupeZ(u8, "/tmp/XXXXXX")));

const result1 = try std.ChildProcess.exec(.{
.allocator = alloc,
.cwd = path,
Expand Down
13 changes: 12 additions & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,13 @@ pub fn main() !void {
std.debug.assert(oa2.clients.len >= current.len);
var i: usize = 0;
while (i < current.len) : (i += 1) {
std.debug.assert(std.mem.eql(u8, oa2.clients[i].provider.domain(), current[i].domain));
const p = oa2.clients[i].provider;
std.log.info("Remote #{d} is now live with {s}", .{ i + 1, p.id });
std.debug.assert(std.mem.eql(u8, p.domain(), current[i].domain));
}
while (i < oa2.clients.len) : (i += 1) {
const idp = oa2.clients[i].provider;
std.log.info("Remote +{d} is now live with {s}", .{ i + 1, idp.id });
_ = try db.Remote.create(alloc, oa2IdToRemoTy(idp.id), idp.domain());
}
}
Expand Down Expand Up @@ -134,6 +137,13 @@ fn parseBoolFlag(comptime flagName: string, default: bool) bool {
fn oa2IdToRemoTy(id: string) db.Remote.Type {
if (std.mem.eql(u8, id, "github.com")) return .github;

if (std.mem.indexOfScalar(u8, id, ',')) |ind| {
if (std.meta.stringToEnum(db.Remote.Type, id[0..ind])) |t| {
return t;
}
std.debug.panic("unsupported client provider: {s}", .{id[0..ind]});
}

std.debug.panic("unsupported client provider: {s}", .{id});
}

Expand Down Expand Up @@ -162,6 +172,7 @@ pub fn pek_tree_url(alloc: std.mem.Allocator, writer: std.ArrayList(u8).Writer,
_ = alloc;
return switch (remo.type) {
.github => try writer.print("https://github.com/{s}/tree/{s}", .{ repo, commit }),
.gitea => try writer.print("https://{s}/{s}/src/commit/{s}", .{ remo.domain, repo, commit }),
};
}

Expand Down

0 comments on commit f212532

Please sign in to comment.