deterministically set up working branch

This commit is contained in:
Colin McDonnell
2025-11-20 16:31:00 -08:00
parent 6c6b7b0b2d
commit 0ce1d9fd7b
4 changed files with 49 additions and 1 deletions
+1
View File
@@ -16,6 +16,7 @@ You do not add unecessary comments, tests, or documentation unless explicitly pr
You adapt your writing style to the style of your coworkers, while never being unprofessional. You adapt your writing style to the style of your coworkers, while never being unprofessional.
You run in a non-interactive environment: complete tasks autonomously without asking follow-up questions. You run in a non-interactive environment: complete tasks autonomously without asking follow-up questions.
You make reasonable assumptions when details are missing, but fail with an explicit error if critical information is missing (e.g. user asks to review a PR but does not provide a link or ID). You make reasonable assumptions when details are missing, but fail with an explicit error if critical information is missing (e.g. user asks to review a PR but does not provide a link or ID).
Never push commits directly to protected branches: main, master, production. Always create a feature branch.
## SECURITY ## SECURITY
+6
View File
@@ -46,6 +46,7 @@ export type PayloadEvent =
pr_number: number; pr_number: number;
pr_title: string; pr_title: string;
pr_body: string | null; pr_body: string | null;
branch: string;
[key: string]: any; [key: string]: any;
} }
| { | {
@@ -53,6 +54,7 @@ export type PayloadEvent =
pr_number: number; pr_number: number;
pr_title: string; pr_title: string;
pr_body: string | null; pr_body: string | null;
branch: string;
[key: string]: any; [key: string]: any;
} }
| { | {
@@ -63,6 +65,7 @@ export type PayloadEvent =
review_state: string; review_state: string;
review_comments: any[]; review_comments: any[];
context: any; context: any;
branch: string;
[key: string]: any; [key: string]: any;
} }
| { | {
@@ -72,6 +75,7 @@ export type PayloadEvent =
comment_id: number; comment_id: number;
comment_body: string; comment_body: string;
thread?: any; thread?: any;
branch: string;
[key: string]: any; [key: string]: any;
} }
| { | {
@@ -100,6 +104,7 @@ export type PayloadEvent =
comment_id: number; comment_id: number;
comment_body: string; comment_body: string;
issue_number: number; issue_number: number;
branch?: string;
[key: string]: any; [key: string]: any;
} }
| { | {
@@ -108,6 +113,7 @@ export type PayloadEvent =
pr_title: string; pr_title: string;
pr_body: string | null; pr_body: string | null;
pull_request: any; pull_request: any;
branch: string;
check_suite: { check_suite: {
id: number; id: number;
head_sha: string; head_sha: string;
+2 -1
View File
@@ -17,7 +17,7 @@ import {
revokeInstallationToken, revokeInstallationToken,
setupGitHubInstallationToken, setupGitHubInstallationToken,
} from "./utils/github.ts"; } from "./utils/github.ts";
import { setupGitAuth, setupGitConfig } from "./utils/setup.ts"; import { setupGitAuth, setupGitBranch, setupGitConfig } from "./utils/setup.ts";
// runtime validation using agents (needed for ArkType) // runtime validation using agents (needed for ArkType)
// Note: The AgentName type is defined in external.ts, this is the runtime validator // Note: The AgentName type is defined in external.ts, this is the runtime validator
@@ -57,6 +57,7 @@ export async function main(inputs: Inputs): Promise<MainResult> {
setupMcpLogPolling(ctx); setupMcpLogPolling(ctx);
ctx.payload = parsePayload(inputs); ctx.payload = parsePayload(inputs);
setupGitBranch(ctx.payload);
setupMcpServers(ctx); setupMcpServers(ctx);
await installAgentCli(ctx); await installAgentCli(ctx);
validateApiKey(ctx); validateApiKey(ctx);
+40
View File
@@ -1,5 +1,6 @@
import { execSync } from "node:child_process"; import { execSync } from "node:child_process";
import { existsSync, rmSync } from "node:fs"; import { existsSync, rmSync } from "node:fs";
import type { Payload } from "../external.ts";
import { log } from "./cli.ts"; import { log } from "./cli.ts";
import type { RepoContext } from "./github.ts"; import type { RepoContext } from "./github.ts";
import { $ } from "./shell.ts"; import { $ } from "./shell.ts";
@@ -91,3 +92,42 @@ export function setupGitAuth(githubToken: string, repoContext: RepoContext): voi
$("git", ["remote", "set-url", "origin", remoteUrl]); $("git", ["remote", "set-url", "origin", remoteUrl]);
log.info("✓ Updated remote URL with authentication token"); log.info("✓ Updated remote URL with authentication token");
} }
/**
* Setup git branch based on payload event context
* Automatically checks out the appropriate branch before agent execution
*/
export function setupGitBranch(payload: Payload): void {
// Only set up git branch in GitHub Actions environment
// In local testing, this might interfere with local git state
if (!process.env.GITHUB_ACTIONS) {
return;
}
const branch = payload.event.branch;
if (!branch) {
log.debug("No branch specified in payload, using default branch");
return;
}
log.info(`🌿 Setting up git branch: ${branch}`);
try {
// Fetch the branch from origin
log.debug(`Fetching branch from origin: ${branch}`);
execSync(`git fetch origin ${branch}`, { stdio: "pipe" });
// Checkout the branch, creating local tracking branch
log.debug(`Checking out branch: ${branch}`);
execSync(`git checkout -B ${branch} origin/${branch}`, { stdio: "pipe" });
log.info(`✓ Successfully checked out branch: ${branch}`);
} catch (error) {
// If git operations fail, log warning but don't fail the action
// The agent might still be able to work with the default branch
log.warning(
`Failed to checkout branch ${branch}: ${error instanceof Error ? error.message : String(error)}`
);
}
}