* fix: fall back to repo default_branch instead of hardcoded "main" When no explicit base_branch input is provided, the action previously fell back to a hardcoded "main", which fails on repositories whose default branch is named differently (e.g. "master", "develop"). This reads repository.default_branch from the GitHub event payload (populated once in parseGitHubContext) and uses it as the fallback in all three callsites: agent/index.ts, run.ts, and update-comment-link.ts. Explicit env/input precedence is preserved; "main" remains only as a last-resort defensive fallback if the payload somehow lacks the field. * test: drop unused BASE_BRANCH env handling from default_branch test agent/index.ts no longer reads process.env.BASE_BRANCH directly (it now goes through context.inputs.baseBranch which is set on the mock context), so saving/clearing/restoring that env var in the regression test is dead code.
135 lines
4.4 KiB
TypeScript
135 lines
4.4 KiB
TypeScript
import { mkdir, writeFile } from "fs/promises";
|
|
import { prepareMcpConfig } from "../../mcp/install-mcp-server";
|
|
import { parseAllowedTools } from "./parse-tools";
|
|
import {
|
|
configureGitAuth,
|
|
setupSshSigning,
|
|
} from "../../github/operations/git-config";
|
|
import { checkHumanActor } from "../../github/validation/actor";
|
|
import type { GitHubContext } from "../../github/context";
|
|
import type { Octokits } from "../../github/api/client";
|
|
|
|
/**
|
|
* Prepares the agent mode execution context.
|
|
*
|
|
* Agent mode runs whenever an explicit prompt is provided in the workflow configuration.
|
|
* It bypasses the standard @claude mention checking and comment tracking used by tag mode,
|
|
* providing direct access to Claude Code for automation workflows.
|
|
*/
|
|
export async function prepareAgentMode({
|
|
context,
|
|
octokit,
|
|
githubToken,
|
|
}: {
|
|
context: GitHubContext;
|
|
octokit: Octokits;
|
|
githubToken: string;
|
|
}) {
|
|
// Check if actor is human (prevents bot-triggered loops)
|
|
await checkHumanActor(octokit.rest, context);
|
|
|
|
// Configure git authentication for agent mode (same as tag mode)
|
|
// SSH signing takes precedence if provided
|
|
const useSshSigning = !!context.inputs.sshSigningKey;
|
|
const useApiCommitSigning = context.inputs.useCommitSigning && !useSshSigning;
|
|
|
|
if (useSshSigning) {
|
|
// Setup SSH signing for commits
|
|
await setupSshSigning(context.inputs.sshSigningKey);
|
|
|
|
// Still configure git auth for push operations (user/email and remote URL)
|
|
const user = {
|
|
login: context.inputs.botName,
|
|
id: parseInt(context.inputs.botId),
|
|
};
|
|
try {
|
|
await configureGitAuth(githubToken, context, user);
|
|
} catch (error) {
|
|
console.error("Failed to configure git authentication:", error);
|
|
// Continue anyway - git operations may still work with default config
|
|
}
|
|
} else if (!useApiCommitSigning) {
|
|
// Use bot_id and bot_name from inputs directly
|
|
const user = {
|
|
login: context.inputs.botName,
|
|
id: parseInt(context.inputs.botId),
|
|
};
|
|
|
|
try {
|
|
// Use the shared git configuration function
|
|
await configureGitAuth(githubToken, context, user);
|
|
} catch (error) {
|
|
console.error("Failed to configure git authentication:", error);
|
|
// Continue anyway - git operations may still work with default config
|
|
}
|
|
}
|
|
|
|
// Create prompt directory
|
|
await mkdir(`${process.env.RUNNER_TEMP || "/tmp"}/claude-prompts`, {
|
|
recursive: true,
|
|
});
|
|
|
|
// Write the prompt file - use the user's prompt directly
|
|
const promptContent =
|
|
context.inputs.prompt ||
|
|
`Repository: ${context.repository.owner}/${context.repository.repo}`;
|
|
|
|
await writeFile(
|
|
`${process.env.RUNNER_TEMP || "/tmp"}/claude-prompts/claude-prompt.txt`,
|
|
promptContent,
|
|
);
|
|
|
|
// Parse allowed tools from user's claude_args
|
|
const userClaudeArgs = process.env.CLAUDE_ARGS || "";
|
|
const allowedTools = parseAllowedTools(userClaudeArgs);
|
|
|
|
// Check for branch info from environment variables (useful for auto-fix workflows)
|
|
const claudeBranch = process.env.CLAUDE_BRANCH || undefined;
|
|
const defaultBranch = context.repository.default_branch || "main";
|
|
const baseBranch = context.inputs.baseBranch || defaultBranch;
|
|
|
|
// Detect current branch from GitHub environment
|
|
const currentBranch =
|
|
claudeBranch ||
|
|
process.env.GITHUB_HEAD_REF ||
|
|
process.env.GITHUB_REF_NAME ||
|
|
defaultBranch;
|
|
|
|
// Get our GitHub MCP servers config
|
|
const ourMcpConfig = await prepareMcpConfig({
|
|
githubToken,
|
|
owner: context.repository.owner,
|
|
repo: context.repository.repo,
|
|
branch: currentBranch,
|
|
baseBranch: baseBranch,
|
|
claudeCommentId: undefined, // No tracking comment in agent mode
|
|
allowedTools,
|
|
mode: "agent",
|
|
context,
|
|
});
|
|
|
|
// Build final claude_args with multiple --mcp-config flags
|
|
let claudeArgs = "";
|
|
|
|
// Add our GitHub servers config if we have any
|
|
const ourConfig = JSON.parse(ourMcpConfig);
|
|
if (ourConfig.mcpServers && Object.keys(ourConfig.mcpServers).length > 0) {
|
|
const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''");
|
|
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
|
}
|
|
|
|
// Append user's claude_args (which may have more --mcp-config flags)
|
|
claudeArgs = `${claudeArgs} ${userClaudeArgs}`.trim();
|
|
|
|
return {
|
|
commentId: undefined,
|
|
branchInfo: {
|
|
baseBranch: baseBranch,
|
|
currentBranch: baseBranch, // Use base branch as current when creating new branch
|
|
claudeBranch: claudeBranch,
|
|
},
|
|
mcpConfig: ourMcpConfig,
|
|
claudeArgs,
|
|
};
|
|
}
|