Files
claude-code-gitea-action/src/entrypoints/prepare.ts
T
Ashwin Bhat e409c57d90 feat: add mcp_config input that merges with existing mcp server (#96)
* feat: add mcp_config input that merges with existing mcp server

- Add mcp_config input parameter to action.yml 
- Modify prepareMcpConfig() to accept and merge additional config
- Provided config overrides built-in servers in case of naming collisions
- Pass MCP_CONFIG environment variable from action to prepare step

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* refactor: improve MCP config validation and merging logic

- Add JSON validation to ensure parsed config is an object
- Simplify merge logic with explicit mcpServers merging
- Enhance error logging with config preview for debugging

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* refactor: improve MCP config logging per review feedback

- Remove configPreview from error logging to avoid cluttering output
- Add informational log when merging MCP server configurations
- Simplify error message for failed config parsing

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* test: add comprehensive unit tests for prepareMcpConfig

Add tests covering:
- Basic functionality with no additional config
- Valid JSON merging scenarios
- Invalid JSON handling
- Empty/null config handling
- Server name collision scenarios
- Complex nested configurations
- Environment variable handling

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* docs: add mcp_config example with sequential-thinking server

- Add mcp_config to inputs table
- Add example section showing how to use mcp_config with sequential-thinking MCP server
- Include clear explanation that custom servers override built-in servers

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* readme

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
2025-06-02 09:03:45 -07:00

108 lines
3.4 KiB
TypeScript

#!/usr/bin/env bun
/**
* Prepare the Claude action by checking trigger conditions, verifying human actor,
* and creating the initial tracking comment
*/
import * as core from "@actions/core";
import { setupGitHubToken } from "../github/token";
import { checkTriggerAction } from "../github/validation/trigger";
import { checkHumanActor } from "../github/validation/actor";
import { checkWritePermissions } from "../github/validation/permissions";
import { createInitialComment } from "../github/operations/comments/create-initial";
import { setupBranch } from "../github/operations/branch";
import { updateTrackingComment } from "../github/operations/comments/update-with-branch";
import { prepareMcpConfig } from "../mcp/install-mcp-server";
import { createPrompt } from "../create-prompt";
import { createOctokit } from "../github/api/client";
import { fetchGitHubData } from "../github/data/fetcher";
import { parseGitHubContext } from "../github/context";
async function run() {
try {
// Step 1: Setup GitHub token
const githubToken = await setupGitHubToken();
const octokit = createOctokit(githubToken);
// Step 2: Parse GitHub context (once for all operations)
const context = parseGitHubContext();
// Step 3: Check write permissions
const hasWritePermissions = await checkWritePermissions(
octokit.rest,
context,
);
if (!hasWritePermissions) {
throw new Error(
"Actor does not have write permissions to the repository",
);
}
// Step 4: Check trigger conditions
const containsTrigger = await checkTriggerAction(context);
if (!containsTrigger) {
console.log("No trigger found, skipping remaining steps");
return;
}
// Step 5: Check if actor is human
await checkHumanActor(octokit.rest, context);
// Step 6: Create initial tracking comment
const commentId = await createInitialComment(octokit.rest, context);
// Step 7: Fetch GitHub data (once for both branch setup and prompt creation)
const githubData = await fetchGitHubData({
octokits: octokit,
repository: `${context.repository.owner}/${context.repository.repo}`,
prNumber: context.entityNumber.toString(),
isPR: context.isPR,
});
// Step 8: Setup branch
const branchInfo = await setupBranch(octokit, githubData, context);
// Step 9: Update initial comment with branch link (only for issues that created a new branch)
if (branchInfo.claudeBranch) {
await updateTrackingComment(
octokit,
context,
commentId,
branchInfo.claudeBranch,
);
}
// Step 10: Create prompt file
await createPrompt(
commentId,
branchInfo.baseBranch,
branchInfo.claudeBranch,
githubData,
context,
);
// Step 11: Get MCP configuration
const additionalMcpConfig = process.env.MCP_CONFIG || "";
const mcpConfig = await prepareMcpConfig(
githubToken,
context.repository.owner,
context.repository.repo,
branchInfo.currentBranch,
additionalMcpConfig,
);
core.setOutput("mcp_config", mcpConfig);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
core.setFailed(`Prepare step failed with error: ${errorMessage}`);
// Also output the clean error message for the action to capture
core.setOutput("prepare_error", errorMessage);
process.exit(1);
}
}
if (import.meta.main) {
run();
}