History

Initial commit

Pranit committed 3 months ago

Commit 439f83cNo parent (first commit)807 files · +798007 −-10Browse files

Showing the changes to src/core/github/github_workflows.zig (1 of 807 files). Show all

Unified · Split

src/core/github/github_workflows.zig+115−0
@@ -0,0 +1,115 @@
1const std = @import("std");
2const git_context = @import("git_context.zig");
3const types = @import("../shared/types.zig");
4
5const Allocator = std.mem.Allocator;
6const ConversationLanguage = types.ConversationLanguage;
7
8pub const Workflow = enum {
9 pull_request,
10 issue,
11};
12
13const PromptSnapshot = struct {
14 in_git_repo: bool,
15 text: []const u8,
16};
17
18pub fn buildPrompt(alloc: Allocator, workflow: Workflow, language: ConversationLanguage, context: []const u8) ![]u8 {
19 const snapshot = try git_context.snapshot(alloc);
20 defer snapshot.deinit(alloc);
21 return buildPromptFromSnapshot(alloc, workflow, language, context, .{
22 .in_git_repo = snapshot.in_git_repo,
23 .text = snapshot.text,
24 });
25}
26
27fn buildPromptFromSnapshot(alloc: Allocator, workflow: Workflow, language: ConversationLanguage, context: []const u8, snapshot: PromptSnapshot) ![]u8 {
28 _ = language;
29 const trimmed = std.mem.trim(u8, context, " \t\r\n");
30 if (workflow == .pull_request and !snapshot.in_git_repo) return error.NotGitRepository;
31 return switch (workflow) {
32 .pull_request => buildPullRequestPrompt(alloc, trimmed, snapshot.text),
33 .issue => buildIssuePrompt(alloc, trimmed, snapshot.text),
34 };
35}
36
37fn buildPullRequestPrompt(alloc: Allocator, context: []const u8, snapshot_text: []const u8) ![]u8 {
38 return if (context.len > 0)
39 std.fmt.allocPrint(alloc, "Draft a GitHub pull request for the current branch. Reply in the same natural language as the current session. Additional context: {s}. Use this prepared git snapshot first and avoid shell commands unless they are truly necessary:\n\n{s}\n\nIf you need more context, read relevant files. Return only: Title, blank line, then a GitHub-flavored Markdown body with sections '## Summary' and '## Testing'. Do not create the PR with gh or publish anything unless I explicitly ask you to.", .{ context, snapshot_text })
40 else
41 std.fmt.allocPrint(alloc, "Draft a GitHub pull request for the current branch. Reply in the same natural language as the current session. Use this prepared git snapshot first and avoid shell commands unless they are truly necessary:\n\n{s}\n\nIf you need more context, read relevant files. Return only: Title, blank line, then a GitHub-flavored Markdown body with sections '## Summary' and '## Testing'. Do not create the PR with gh or publish anything unless I explicitly ask you to.", .{snapshot_text});
42}
43
44fn buildIssuePrompt(alloc: Allocator, context: []const u8, snapshot_text: []const u8) ![]u8 {
45 return if (context.len > 0)
46 std.fmt.allocPrint(alloc, "Draft a GitHub issue from the current context. Reply in the same natural language as the current session. Additional context: {s}. Use this prepared git snapshot first and avoid shell commands unless they are truly necessary:\n\n{s}\n\nIf you need more context, inspect relevant files, errors, or logs. Return only: Title, blank line, then a GitHub-flavored Markdown body with sections '## Summary', '## Steps to Reproduce', '## Expected', and '## Actual'. Do not create the issue with gh or publish anything unless I explicitly ask you to.", .{ context, snapshot_text })
47 else
48 std.fmt.allocPrint(alloc, "Draft a GitHub issue from the current context. Reply in the same natural language as the current session. Use this prepared git snapshot first and avoid shell commands unless they are truly necessary:\n\n{s}\n\nIf you need more context, inspect relevant files, errors, or logs. Return only: Title, blank line, then a GitHub-flavored Markdown body with sections '## Summary', '## Steps to Reproduce', '## Expected', and '## Actual'. Do not create the issue with gh or publish anything unless I explicitly ask you to.", .{snapshot_text});
49}
50
51fn expectContains(haystack: []const u8, needle: []const u8) !void {
52 try std.testing.expect(std.mem.find(u8, haystack, needle) != null);
53}
54
55fn expectNotContains(haystack: []const u8, needle: []const u8) !void {
56 try std.testing.expect(std.mem.find(u8, haystack, needle) == null);
57}
58
59test "build pull request prompt includes additional context" {
60 const prompt = buildPrompt(std.testing.allocator, .pull_request, ConversationLanguage.default(), "ready for review") catch |err| switch (err) {
61 error.NotGitRepository => return,
62 else => return err,
63 };
64 defer std.testing.allocator.free(prompt);
65
66 try expectContains(prompt, "ready for review");
67 try expectContains(prompt, "## Summary");
68}
69
70test "build issue prompt defaults cleanly without context" {
71 const prompt = try buildPrompt(std.testing.allocator, .issue, ConversationLanguage.default(), "");
72 defer std.testing.allocator.free(prompt);
73
74 try expectContains(prompt, "GitHub issue");
75 try expectContains(prompt, "## Steps to Reproduce");
76}
77
78test "pull request prompt preserves active context and section contract" {
79 const prompt = try buildPromptFromSnapshot(std.testing.allocator, .pull_request, ConversationLanguage.literal("es"), " ready for review \n", .{
80 .in_git_repo = true,
81 .text = "Git snapshot\nBranch: feature\n",
82 });
83 defer std.testing.allocator.free(prompt);
84
85 try expectContains(prompt, "Additional context: ready for review.");
86 try expectContains(prompt, "Git snapshot\nBranch: feature\n");
87 try expectContains(prompt, "## Summary");
88 try expectContains(prompt, "## Testing");
89 try expectNotContains(prompt, "## Steps to Reproduce");
90 try expectContains(prompt, "Do not create the PR with gh or publish anything unless I explicitly ask you to.");
91}
92
93test "pull request prompt requires a git repository" {
94 try std.testing.expectError(error.NotGitRepository, buildPromptFromSnapshot(std.testing.allocator, .pull_request, ConversationLanguage.default(), "", .{
95 .in_git_repo = false,
96 .text = "Git snapshot\nBranch: unavailable\n",
97 }));
98}
99
100test "issue prompt works outside git and omits empty context clause" {
101 const prompt = try buildPromptFromSnapshot(std.testing.allocator, .issue, ConversationLanguage.default(), " \t\r\n", .{
102 .in_git_repo = false,
103 .text = "Git snapshot\nBranch: unavailable\n",
104 });
105 defer std.testing.allocator.free(prompt);
106
107 try expectContains(prompt, "Draft a GitHub issue from the current context.");
108 try expectContains(prompt, "Git snapshot\nBranch: unavailable\n");
109 try expectContains(prompt, "## Summary");
110 try expectContains(prompt, "## Steps to Reproduce");
111 try expectContains(prompt, "## Expected");
112 try expectContains(prompt, "## Actual");
113 try expectNotContains(prompt, "Additional context:");
114 try expectContains(prompt, "Do not create the issue with gh or publish anything unless I explicitly ask you to.");
115}