|
|
9 сар өмнө | |
|---|---|---|
| client | 9 сар өмнө | |
| docs | 9 сар өмнө | |
| examples | 9 сар өмнө | |
| scripts | 9 сар өмнө | |
| src | 9 сар өмнө | |
| .env.example | 9 сар өмнө | |
| .gitignore | 9 сар өмнө | |
| .mcp-gogs.json.example | 9 сар өмнө | |
| CLAUDE.md | 9 сар өмнө | |
| README.md | 9 сар өмнө | |
| SYSTEMD.md | 9 сар өмнө | |
| agent-manager.service | 9 сар өмнө | |
| commands.json | 9 сар өмнө | |
| commands.json.example | 9 сар өмнө | |
| install.sh | 9 сар өмнө | |
| package-lock.json | 9 сар өмнө | |
| package.json | 9 сар өмнө | |
| show-example-prompts.sh | 9 сар өмнө | |
| test-signature-verification.js | 9 сар өмнө | |
| uninstall.sh | 9 сар өмнө |
A modular Node.js server for receiving and processing Gogs webhooks. The server logs all incoming webhooks to the console, executes configured commands based on webhook events, and provides an extensible callback system for custom event handling.
commands.jsonnpm install
Copy the example files:
cp .env.example .env
cp commands.json.example commands.json
Edit .env to enable/disable webhook events
Edit commands.json to configure commands for webhook events (see Configuration section below)
Start the server:
npm start
The server will start on port 3000 and execute configured commands when webhooks are received.
npm run dev
For production deployments, you can run the server as a systemd service. This provides:
See SYSTEMD.md for detailed installation and configuration instructions.
Quick example:
# Install the service
sudo cp agent-manager.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable agent-manager
sudo systemctl start agent-manager
# View logs
journalctl -u agent-manager -f -n100
The server uses two configuration files:
.env - Enable/disable webhook events and server settingscommands.json - Define commands to execute for each event type.env)HOST=0.0.0.0
PORT=3000
WEBHOOK_PATH=/webhook
WEBHOOK_SECRET=your-secret-here
HOST - The network interface to bind to (default: 0.0.0.0 for all interfaces, use 127.0.0.1 for localhost only)PORT - The port number to listen on (default: 3000)WEBHOOK_PATH - The URL path for webhooks (default: /webhook)WEBHOOK_SECRET - Optional secret for webhook signature verification (see Security section below).env)WEBHOOK_PUSH_ENABLED=true
WEBHOOK_PULL_REQUEST_ENABLED=false
WEBHOOK_CREATE_ENABLED=false
WEBHOOK_DELETE_ENABLED=false
WEBHOOK_RELEASE_ENABLED=false
WEBHOOK_ISSUES_ENABLED=false
WEBHOOK_ISSUE_COMMENT_ENABLED=false
WEBHOOK_GLOBAL_ENABLED=false
commands.json)Commands are configured in a JSON file with the following structure:
{
"commands": {
"push": [
{
"name": "deploy-production",
"description": "Deploy to production on main branch",
"type": "shell",
"command": "/path/to/deploy.sh",
"args": ["{{branch}}", "{{repo}}", "{{pusher}}"],
"cwd": "/workspace",
"timeout": 600000,
"filterBranch": "main"
}
],
"issues": [
{
"name": "process-issue",
"description": "Process issue with Node.js script",
"type": "node",
"command": "./scripts/process-issue.js",
"args": ["--repo", "{{repo}}", "--issue", "{{issue_number}}"],
"cwd": null,
"timeout": 300000,
"filterBranch": null
}
]
}
}
Command Fields:
name - Unique identifier for the commanddescription - Human-readable descriptiontype - Either "shell" (bash script) or "node" (Node.js script)command - The command or script to executeargs - Array of arguments (supports variable substitution)cwd - Working directory (null uses project root)timeout - Timeout in millisecondsfilterBranch - Only run for specific branch (null = all branches)Available Variables:
{{repo}} - Repository name (e.g., "my-repo"){{full_repo}} - Full repository name (e.g., "user/my-repo"){{repo_owner}} - Repository owner username (e.g., "user"){{branch}} - Branch name (e.g., "main", "feature/new-feature"){{pusher}} - Username of person who triggered the event{{event}} - Event type (e.g., "push", "pull_request"){{commit}} - Latest commit hash (short, for push events){{commit_msg}} - Latest commit message (for push events){{pr_number}} - Pull request number (for PR events){{pr_action}} - Pull request action (opened, closed, etc.){{tag}} - Tag name (for create/delete tag events){{ref_type}} - "branch" or "tag"{{issue_number}} - Issue number (for issue events){{issue_title}} - Issue title (for issue events){{issue_action}} - Issue action (opened, closed, reopened, etc.){{issue_body}} - Issue description/body (for issue events){{issue_assignee}} - Username of the person assigned to the issue (for issue events){{comment_body}} - Comment text (for issue_comment events)Supported Event Types:
push - Push eventspull_request - Pull request eventscreate - Branch/tag creationdelete - Branch/tag deletionrelease - Release eventsissues - Issue events (opened, closed, reopened, etc.)issue_comment - Issue comment eventsglobal - All eventsPOST /webhook - Webhook endpointGET /health - Health check endpointThe server supports HMAC-SHA256 signature verification to ensure webhooks are authentic and haven't been tampered with.
When you configure a secret in Gogs webhook settings and in your .env file, Gogs will sign each webhook request with an HMAC-SHA256 signature and send it in the X-Gogs-Signature header. The server verifies this signature before processing the webhook.
Configure Secret in .env:
WEBHOOK_SECRET=your-secure-random-string
Configure Secret in Gogs:
Go to your repository settings → Webhooks
Edit or create a webhook
Set the same secret value in the "Secret" field
Set Content Type to application/json
X-Gogs-Signature header and rejects webhooks with missing or invalid signatures (HTTP 401)The server:
X-Gogs-Signature header using a timing-safe comparisonThis ensures:
The webhook server uses a persistent job queue to ensure reliable and sequential command execution:
queue.json after every changeThe queue state is stored in queue.json in the project root:
{
"queue": [
{
"id": 1,
"eventType": "push",
"status": "pending",
"createdAt": "2025-10-28T12:00:00.000Z"
}
],
"jobIdCounter": 5,
"lastSaved": "2025-10-28T12:05:00.000Z"
}
This file is automatically managed and should not be manually edited. It's excluded from git via .gitignore.
.env:
WEBHOOK_PUSH_ENABLED=true
commands.json:
{
"commands": {
"push": [
{
"name": "deploy-production",
"description": "Deploy to production on main branch",
"type": "shell",
"command": "/home/deploy/deploy.sh",
"args": ["{{repo}}", "{{branch}}", "{{commit}}"],
"cwd": null,
"timeout": 600000,
"filterBranch": "main"
}
]
}
}
deploy.sh:
#!/bin/bash
REPO=$1
BRANCH=$2
COMMIT=$3
echo "Deploying $REPO from $BRANCH (commit: $COMMIT)"
cd /var/www/$REPO
git pull origin $BRANCH
npm install
npm run build
systemctl restart $REPO
.env:
WEBHOOK_GLOBAL_ENABLED=true
commands.json:
{
"commands": {
"global": [
{
"name": "slack-notification",
"description": "Send Slack notification for all events",
"type": "shell",
"command": "curl",
"args": ["-X", "POST", "https://api.slack.com/webhook", "-d", "{\"text\":\"{{event}} in {{repo}} by {{pusher}}\"}"],
"cwd": null,
"timeout": 30000,
"filterBranch": null
}
]
}
}
.env:
WEBHOOK_PULL_REQUEST_ENABLED=true
commands.json:
{
"commands": {
"pull_request": [
{
"name": "run-tests",
"description": "Run automated tests on pull request",
"type": "node",
"command": "./scripts/run-tests.js",
"args": ["--repo", "{{repo}}", "--pr", "{{pr_number}}", "--author", "{{pusher}}"],
"cwd": "/home/ci",
"timeout": 900000,
"filterBranch": null
}
]
}
}
The server is designed to be easily extended with custom callbacks. See examples/with-callbacks.js for a complete example.
import { WebhookServer } from './src/server.js';
const server = new WebhookServer({ port: 3000 });
const handler = server.getHandler();
// Handle push events
handler.on('push', async (payload, headers) => {
console.log('Push to:', payload.repository.name);
console.log('Commits:', payload.commits.length);
// Your custom logic here
});
// Handle pull request events
handler.on('pull_request', async (payload, headers) => {
console.log('PR:', payload.action);
// Your custom logic here
});
server.start();
// Handle all events
handler.onAny(async (eventType, payload, headers) => {
console.log('Received event:', eventType);
// Send to analytics, external logging, etc.
});
node examples/with-callbacks.js
http://your-server:3000/webhookapplication/jsonpush - Repository pushcreate - Branch or tag creationdelete - Branch or tag deletionpull_request - Pull request actionsissues - Issue actionsissue_comment - Issue comment actionsrelease - Release actions.
├── src/
│ ├── index.js # Main entry point
│ ├── server.js # HTTP server implementation
│ ├── webhookHandler.js # Webhook processing and callbacks
│ ├── jobQueue.js # Persistent job queue with FIFO processing
│ ├── commandExecutor.js # Command execution with variable substitution
│ ├── config.js # Configuration loader (.env and commands.json)
│ └── logger.js # Logging utility
├── client/ # TypeScript-based Claude Agent SDK client
│ ├── src/
│ │ ├── index.ts # CLI entry point
│ │ ├── claude-client.ts # Main Claude Agent SDK client
│ │ ├── config.ts # Configuration management
│ │ ├── mcpConfigManager.ts # MCP configuration manager
│ │ └── types.ts # TypeScript type definitions
│ └── dist/ # Compiled JavaScript (auto-generated)
├── scripts/
│ └── handle-issue-ts.sh # TypeScript issue handler script
├── examples/
│ ├── with-callbacks.js # Example with custom callbacks
│ ├── mcp-config-default.json # Example default MCP config
│ ├── mcp-config-multi-server.json # Example multi-server MCP config
│ └── MCP-CONFIG.md # MCP configuration guide
├── .env.example # Example environment configuration
├── commands.json.example # Example command configuration
├── .env # Your environment configuration (not in git)
├── commands.json # Your command configuration (not in git)
├── queue.json # Queue state (auto-generated, gitignored)
├── package.json
└── README.md
src/server.js)src/webhookHandler.js)src/jobQueue.js)queue.jsonsrc/commandExecutor.js)src/logger.js)src/config.js)The client/ directory contains a TypeScript-based Claude Agent SDK client for AI-powered issue automation.
${VAR_NAME} syntaxcd client
npm install
npm run build
The client supports three levels of MCP server configuration:
~/.config/agent-manager/mcp/{owner}/{repo}.json~/.config/agent-manager/mcp/default.jsonExample MCP Configuration:
{
"mcpServers": {
"gogs": {
"type": "stdio",
"command": "node",
"args": ["/data/gogs-mcp/dist/index.js"],
"env": {}
},
"database": {
"type": "stdio",
"command": "node",
"args": ["/path/to/db-mcp/dist/index.js"],
"env": {
"DB_HOST": "${DB_HOST}",
"DB_PASSWORD": "${DB_PASSWORD}"
}
}
}
}
Key Features:
For detailed MCP configuration guide, see examples/MCP-CONFIG.md.
The TypeScript client is automatically invoked by the webhook server when issues are assigned to Claude. It can also be run manually:
node client/dist/index.js <owner> <repo> <pusher> <issue_number> <issue_title> <issue_body> <issue_action> [comment_body] [assignee]
See client/README.md for more details.
You can test the webhook server using curl:
# Test health check
curl http://localhost:3000/health
# Test webhook with push event
curl -X POST http://localhost:3000/webhook \
-H "Content-Type: application/json" \
-H "X-Gogs-Event: push" \
-H "X-Gogs-Delivery: 12345" \
-d '{
"ref": "refs/heads/main",
"repository": {
"name": "test-repo",
"full_name": "user/test-repo"
},
"pusher": {
"username": "testuser"
},
"commits": [
{
"id": "abc123",
"message": "Test commit"
}
]
}'
ISC