fix issue with SourceHut
This commit is contained in:
parent
a8f802c02f
commit
9197b01e01
1 changed files with 99 additions and 153 deletions
|
@ -178,6 +178,12 @@ const TagData = struct {
|
||||||
commit_id: []const u8,
|
commit_id: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TagInfo = struct {
|
||||||
|
tag_name: []const u8,
|
||||||
|
commit_id: []const u8,
|
||||||
|
index: usize,
|
||||||
|
};
|
||||||
|
|
||||||
fn parseRepoFormat(allocator: Allocator, repo: []const u8) !ParsedRepo {
|
fn parseRepoFormat(allocator: Allocator, repo: []const u8) !ParsedRepo {
|
||||||
// Parse repo format: "~username/reponame" or "username/reponame"
|
// Parse repo format: "~username/reponame" or "username/reponame"
|
||||||
const repo_clean = if (std.mem.startsWith(u8, repo, "~")) repo[1..] else repo;
|
const repo_clean = if (std.mem.startsWith(u8, repo, "~")) repo[1..] else repo;
|
||||||
|
@ -335,6 +341,7 @@ fn getAllReferencesMultiRepo(allocator: Allocator, client: *http.Client, token:
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getAllCommitDatesMultiRepo(allocator: Allocator, client: *http.Client, token: []const u8, repos: []const ParsedRepo, tag_data: []const TagData) !ArrayList([]const u8) {
|
fn getAllCommitDatesMultiRepo(allocator: Allocator, client: *http.Client, token: []const u8, repos: []const ParsedRepo, tag_data: []const TagData) !ArrayList([]const u8) {
|
||||||
|
_ = repos; // unused in this implementation
|
||||||
var commit_dates = ArrayList([]const u8).init(allocator);
|
var commit_dates = ArrayList([]const u8).init(allocator);
|
||||||
errdefer {
|
errdefer {
|
||||||
for (commit_dates.items) |date| {
|
for (commit_dates.items) |date| {
|
||||||
|
@ -347,145 +354,89 @@ fn getAllCommitDatesMultiRepo(allocator: Allocator, client: *http.Client, token:
|
||||||
return commit_dates;
|
return commit_dates;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group commit hashes by repository using simple arrays
|
// Since SourceHut's objects() query automatically resolves tag objects to their target commits,
|
||||||
const RepoCommits = struct {
|
// we need to use a different approach. Let's use the revparse_single query for each tag individually
|
||||||
repo_idx: u32,
|
// but batch them by repository to minimize queries.
|
||||||
commits: ArrayList([]const u8),
|
|
||||||
|
// Group tags by repository
|
||||||
|
const RepoTags = struct {
|
||||||
|
username: []const u8,
|
||||||
|
reponame: []const u8,
|
||||||
|
tags: ArrayList(TagInfo),
|
||||||
};
|
};
|
||||||
|
|
||||||
var repo_commits_list = ArrayList(RepoCommits).init(allocator);
|
var repo_tags_map = ArrayList(RepoTags).init(allocator);
|
||||||
defer {
|
defer {
|
||||||
for (repo_commits_list.items) |*item| {
|
for (repo_tags_map.items) |*item| {
|
||||||
item.commits.deinit();
|
item.tags.deinit();
|
||||||
}
|
}
|
||||||
repo_commits_list.deinit();
|
repo_tags_map.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build mapping of tag_data to repository indices
|
for (tag_data, 0..) |tag, i| {
|
||||||
for (tag_data, 0..) |tag, tag_idx| {
|
// Find or create repo entry
|
||||||
// Find which repository this tag belongs to
|
|
||||||
for (repos, 0..) |repo, repo_idx| {
|
|
||||||
if (std.mem.eql(u8, tag.username, repo.username) and std.mem.eql(u8, tag.reponame, repo.reponame)) {
|
|
||||||
// Find or create entry for this repo
|
|
||||||
var found = false;
|
var found = false;
|
||||||
for (repo_commits_list.items) |*item| {
|
for (repo_tags_map.items) |*repo_tags| {
|
||||||
if (item.repo_idx == repo_idx) {
|
if (std.mem.eql(u8, repo_tags.username, tag.username) and std.mem.eql(u8, repo_tags.reponame, tag.reponame)) {
|
||||||
try item.commits.append(tag.commit_id);
|
try repo_tags.tags.append(TagInfo{ .tag_name = tag.tag_name, .commit_id = tag.commit_id, .index = i });
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
var new_commits = ArrayList([]const u8).init(allocator);
|
var new_tags = ArrayList(TagInfo).init(allocator);
|
||||||
try new_commits.append(tag.commit_id);
|
try new_tags.append(TagInfo{ .tag_name = tag.tag_name, .commit_id = tag.commit_id, .index = i });
|
||||||
try repo_commits_list.append(RepoCommits{
|
try repo_tags_map.append(RepoTags{
|
||||||
.repo_idx = @intCast(repo_idx),
|
.username = tag.username,
|
||||||
.commits = new_commits,
|
.reponame = tag.reponame,
|
||||||
|
.tags = new_tags,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = tag_idx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build GraphQL query with variables for commit hashes grouped by repository
|
// Initialize result array with empty strings
|
||||||
|
for (tag_data) |_| {
|
||||||
|
try commit_dates.append("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a single GraphQL query with all repositories and all their commits using aliases
|
||||||
var query_builder = ArrayList(u8).init(allocator);
|
var query_builder = ArrayList(u8).init(allocator);
|
||||||
defer query_builder.deinit();
|
defer query_builder.deinit();
|
||||||
|
|
||||||
var variables_builder = ArrayList(u8).init(allocator);
|
try query_builder.appendSlice("query {\n");
|
||||||
defer variables_builder.deinit();
|
|
||||||
|
|
||||||
try query_builder.appendSlice("query(");
|
// Build the query with aliases for each repository
|
||||||
try variables_builder.appendSlice("{");
|
for (repo_tags_map.items, 0..) |repo_tags, repo_idx| {
|
||||||
|
try query_builder.writer().print(" repo{d}: user(username: \"{s}\") {{\n", .{ repo_idx, repo_tags.username });
|
||||||
|
try query_builder.writer().print(" repository(name: \"{s}\") {{\n", .{repo_tags.reponame});
|
||||||
|
|
||||||
// Build query variables and structure
|
for (repo_tags.tags.items, 0..) |tag_info, tag_idx| {
|
||||||
var first_var = true;
|
try query_builder.writer().print(" tag{d}_{d}: revparse_single(revspec: \"{s}\") {{\n", .{ repo_idx, tag_idx, tag_info.commit_id });
|
||||||
for (repo_commits_list.items) |item| {
|
try query_builder.appendSlice(" ... on Commit {\n");
|
||||||
if (item.commits.items.len == 0) continue;
|
try query_builder.appendSlice(" committer { time }\n");
|
||||||
|
try query_builder.appendSlice(" }\n");
|
||||||
const var_name = try std.fmt.allocPrint(allocator, "repo{d}Hashes", .{item.repo_idx});
|
try query_builder.appendSlice(" }\n");
|
||||||
defer allocator.free(var_name);
|
|
||||||
|
|
||||||
if (!first_var) {
|
|
||||||
try query_builder.appendSlice(", ");
|
|
||||||
try variables_builder.appendSlice(", ");
|
|
||||||
}
|
|
||||||
first_var = false;
|
|
||||||
|
|
||||||
try query_builder.writer().print("${s}: [String!]!", .{var_name});
|
|
||||||
|
|
||||||
// Build JSON array of commit hashes
|
|
||||||
try variables_builder.writer().print("\"{s}\": [", .{var_name});
|
|
||||||
for (item.commits.items, 0..) |commit, i| {
|
|
||||||
if (i > 0) try variables_builder.appendSlice(", ");
|
|
||||||
try variables_builder.writer().print("\"{s}\"", .{commit});
|
|
||||||
}
|
|
||||||
try variables_builder.appendSlice("]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try query_builder.appendSlice(") {");
|
try query_builder.appendSlice(" }\n");
|
||||||
try variables_builder.appendSlice("}");
|
try query_builder.appendSlice(" }\n");
|
||||||
|
|
||||||
// Build query body
|
|
||||||
for (repo_commits_list.items) |item| {
|
|
||||||
if (item.commits.items.len == 0) continue;
|
|
||||||
|
|
||||||
const repo = repos[item.repo_idx];
|
|
||||||
const alias = try std.fmt.allocPrint(allocator, "repo{d}", .{item.repo_idx});
|
|
||||||
defer allocator.free(alias);
|
|
||||||
const var_name = try std.fmt.allocPrint(allocator, "repo{d}Hashes", .{item.repo_idx});
|
|
||||||
defer allocator.free(var_name);
|
|
||||||
|
|
||||||
const repo_query = try std.fmt.allocPrint(allocator,
|
|
||||||
\\
|
|
||||||
\\ {s}: user(username: "{s}") {{
|
|
||||||
\\ repository(name: "{s}") {{
|
|
||||||
\\ objects(ids: ${s}) {{
|
|
||||||
\\ id
|
|
||||||
\\ ... on Commit {{
|
|
||||||
\\ committer {{
|
|
||||||
\\ time
|
|
||||||
\\ }}
|
|
||||||
\\ }}
|
|
||||||
\\ }}
|
|
||||||
\\ }}
|
|
||||||
\\ }}
|
|
||||||
, .{ alias, repo.username, repo.reponame, var_name });
|
|
||||||
defer allocator.free(repo_query);
|
|
||||||
|
|
||||||
try query_builder.appendSlice(repo_query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try query_builder.appendSlice("\n}");
|
try query_builder.appendSlice("}");
|
||||||
|
|
||||||
// Properly escape the query string for JSON
|
// Create JSON request body
|
||||||
var escaped_query = ArrayList(u8).init(allocator);
|
var json_obj = std.json.ObjectMap.init(allocator);
|
||||||
defer escaped_query.deinit();
|
defer json_obj.deinit();
|
||||||
|
|
||||||
for (query_builder.items) |char| {
|
try json_obj.put("query", std.json.Value{ .string = query_builder.items });
|
||||||
switch (char) {
|
|
||||||
'"' => try escaped_query.appendSlice("\\\""),
|
|
||||||
'\\' => try escaped_query.appendSlice("\\\\"),
|
|
||||||
'\n' => try escaped_query.appendSlice("\\n"),
|
|
||||||
'\r' => try escaped_query.appendSlice("\\r"),
|
|
||||||
'\t' => try escaped_query.appendSlice("\\t"),
|
|
||||||
else => try escaped_query.append(char),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the complete JSON request body manually
|
var json_string = ArrayList(u8).init(allocator);
|
||||||
var request_body = ArrayList(u8).init(allocator);
|
defer json_string.deinit();
|
||||||
defer request_body.deinit();
|
|
||||||
|
|
||||||
try request_body.appendSlice("{\"query\":\"");
|
try std.json.stringify(std.json.Value{ .object = json_obj }, .{}, json_string.writer());
|
||||||
try request_body.appendSlice(escaped_query.items);
|
|
||||||
try request_body.appendSlice("\",\"variables\":");
|
|
||||||
try request_body.appendSlice(variables_builder.items);
|
|
||||||
try request_body.appendSlice("}");
|
|
||||||
|
|
||||||
// Make the GraphQL request
|
// Make the single GraphQL request for all repositories and commits
|
||||||
const response_body = try makeGraphQLRequest(allocator, client, token, request_body.items);
|
const response_body = try makeGraphQLRequest(allocator, client, token, json_string.items);
|
||||||
defer allocator.free(response_body);
|
defer allocator.free(response_body);
|
||||||
|
|
||||||
// Parse the response
|
// Parse the response
|
||||||
|
@ -525,58 +476,53 @@ fn getAllCommitDatesMultiRepo(allocator: Allocator, client: *http.Client, token:
|
||||||
return commit_dates;
|
return commit_dates;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build a simple list of commit_id -> date pairs for quick lookup
|
// Extract dates for each tag using the aliases
|
||||||
const CommitDate = struct {
|
for (repo_tags_map.items, 0..) |repo_tags, repo_idx| {
|
||||||
commit_id: []const u8,
|
const repo_alias = try std.fmt.allocPrint(allocator, "repo{d}", .{repo_idx});
|
||||||
date: []const u8,
|
defer allocator.free(repo_alias);
|
||||||
};
|
|
||||||
var commit_date_list = ArrayList(CommitDate).init(allocator);
|
|
||||||
defer commit_date_list.deinit();
|
|
||||||
|
|
||||||
for (repo_commits_list.items) |item| {
|
const repo_data = data.object.get(repo_alias) orelse continue;
|
||||||
const alias = try std.fmt.allocPrint(allocator, "repo{d}", .{item.repo_idx});
|
|
||||||
defer allocator.free(alias);
|
|
||||||
|
|
||||||
const repo_data = data.object.get(alias) orelse continue;
|
|
||||||
if (repo_data == .null) continue;
|
if (repo_data == .null) continue;
|
||||||
const repository = repo_data.object.get("repository") orelse continue;
|
const repository = repo_data.object.get("repository") orelse continue;
|
||||||
if (repository == .null) continue;
|
if (repository == .null) continue;
|
||||||
const objects = repository.object.get("objects") orelse continue;
|
|
||||||
|
|
||||||
for (objects.array.items) |obj| {
|
for (repo_tags.tags.items, 0..) |tag_info, tag_idx| {
|
||||||
const id = obj.object.get("id") orelse continue;
|
const tag_alias = try std.fmt.allocPrint(allocator, "tag{d}_{d}", .{ repo_idx, tag_idx });
|
||||||
const committer = obj.object.get("committer") orelse continue;
|
defer allocator.free(tag_alias);
|
||||||
const time = committer.object.get("time") orelse continue;
|
|
||||||
|
|
||||||
if (id == .string and time == .string) {
|
const tag_obj = repository.object.get(tag_alias);
|
||||||
try commit_date_list.append(CommitDate{
|
if (tag_obj) |obj| {
|
||||||
.commit_id = id.string,
|
if (obj == .null) continue;
|
||||||
.date = time.string,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now build the result array in the same order as tag_data
|
if (obj.object.get("committer")) |committer| {
|
||||||
for (tag_data) |tag| {
|
if (committer.object.get("time")) |time| {
|
||||||
var found_date: []const u8 = "";
|
if (time == .string) {
|
||||||
for (commit_date_list.items) |item| {
|
// Free the empty string we allocated earlier
|
||||||
if (std.mem.eql(u8, item.commit_id, tag.commit_id)) {
|
if (commit_dates.items[tag_info.index].len > 0) {
|
||||||
found_date = item.date;
|
allocator.free(commit_dates.items[tag_info.index]);
|
||||||
break;
|
}
|
||||||
|
commit_dates.items[tag_info.index] = try allocator.dupe(u8, time.string);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_date.len > 0) {
|
|
||||||
try commit_dates.append(try allocator.dupe(u8, found_date));
|
|
||||||
} else {
|
|
||||||
try commit_dates.append("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return commit_dates;
|
return commit_dates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getSingleCommitDate(allocator: Allocator, client: *http.Client, token: []const u8, username: []const u8, reponame: []const u8, commit_id: []const u8) ![]const u8 {
|
||||||
|
_ = allocator;
|
||||||
|
_ = client;
|
||||||
|
_ = token;
|
||||||
|
_ = username;
|
||||||
|
_ = reponame;
|
||||||
|
_ = commit_id;
|
||||||
|
// This function is no longer used but kept for compatibility
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
fn makeGraphQLRequest(allocator: Allocator, client: *http.Client, token: []const u8, request_body: []const u8) ![]const u8 {
|
fn makeGraphQLRequest(allocator: Allocator, client: *http.Client, token: []const u8, request_body: []const u8) ![]const u8 {
|
||||||
const graphql_url = "https://git.sr.ht/query";
|
const graphql_url = "https://git.sr.ht/query";
|
||||||
const uri = try std.Uri.parse(graphql_url);
|
const uri = try std.Uri.parse(graphql_url);
|
||||||
|
|
Loading…
Add table
Reference in a new issue