|
|
8 mēneši atpakaļ | |
|---|---|---|
| client | 8 mēneši atpakaļ | |
| docs | 9 mēneši atpakaļ | |
| examples | 8 mēneši atpakaļ | |
| scripts | 9 mēneši atpakaļ | |
| src | 8 mēneši atpakaļ | |
| .env.example | 9 mēneši atpakaļ | |
| .gitignore | 9 mēneši atpakaļ | |
| .mcp-gogs.json.example | 9 mēneši atpakaļ | |
| .smtp-config.json.example | 9 mēneši atpakaļ | |
| CLAUDE.md | 8 mēneši atpakaļ | |
| README.md | 9 mēneši atpakaļ | |
| SYSTEMD.md | 9 mēneši atpakaļ | |
| agent-manager.service | 9 mēneši atpakaļ | |
| commands.json | 8 mēneši atpakaļ | |
| commands.json.example | 9 mēneši atpakaļ | |
| email-rules.json.example | 9 mēneši atpakaļ | |
| install.sh | 8 mēneši atpakaļ | |
| package-lock.json | 9 mēneši atpakaļ | |
| package.json | 8 mēneši atpakaļ | |
| show-example-prompts.sh | 9 mēneši atpakaļ | |
| test-signature-verification.js | 9 mēneši atpakaļ | |
| uninstall.sh | 8 mēneši atpakaļ |
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
cp .smtp-config.json.example .smtp-config.json # Optional, for email notifications
cp email-rules.json.example email-rules.json # Optional, for email notifications
Edit .env to enable/disable webhook events
Edit commands.json to configure commands for webhook events (see Configuration section below)
(Optional) Configure email notifications:
.smtp-config.json with your SMTP server settingsemail-rules.json to define email notification rulesStart 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 command execution. The queue supports two operating modes:
Single-Queue Mode (Default)
Multi-Queue Mode (Parallel Per Repository)
QUEUE_PARALLEL_PER_REPOSITORY=true in .envqueue.json after every changeSingle-Queue Mode:
Multi-Queue Mode:
The queue state is stored in queue.json in the project root.
Single-Queue Mode:
{
"queue": [
{
"id": 1,
"eventType": "push",
"status": "pending",
"createdAt": "2025-10-28T12:00:00.000Z"
}
],
"jobIdCounter": 5,
"lastSaved": "2025-10-28T12:05:00.000Z"
}
Multi-Queue Mode:
{
"queues": {
"owner/repo1": {
"queue": [{ "id": 1, "eventType": "push", "status": "pending" }]
},
"owner/repo2": {
"queue": [{ "id": 2, "eventType": "issues", "status": "running" }]
}
},
"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.
The server includes an email notification system that can send emails based on webhook events and configurable conditions.
Email notifications require two configuration files:
.smtp-config.json - SMTP server configuration (excluded from git)email-rules.json - Email notification rules (excluded from git)Copy the example files to get started:
cp .smtp-config.json.example .smtp-config.json
cp email-rules.json.example email-rules.json
.smtp-config.json){
"host": "mail.example.com",
"port": 1025,
"secure": false,
"user": "your-email@example.com",
"pass": "your-password",
"from": "noreply@example.com"
}
Fields:
host - SMTP server hostnameport - SMTP server port (25, 587, 465, etc.)secure - Use TLS from start (true for port 465, false for STARTTLS)user - SMTP usernamepass - SMTP passwordfrom - Email address to send fromemail-rules.json){
"rules": [
{
"name": "mention-notification",
"event": "issue_comment",
"condition": {
"type": "mention",
"value": "username"
},
"recipients": ["{{mentioned_user}}"],
"subject": "You were mentioned in {{full_repo}}#{{issue_number}}",
"body": "Comment by {{sender}}:\n{{comment_body}}"
}
]
}
Rule Fields:
name - Unique identifier for the ruleevent - Webhook event type to trigger oncondition - Condition that must be met (optional)recipients - Array of email addresses or variablessubject - Email subject (supports variables)body - Email body (supports variables)mention - Check if a user is mentioned in the payload:
{
"type": "mention",
"value": "username"
}
branch - Check if event is for a specific branch:
{
"type": "branch",
"value": "main"
}
action - Check if webhook action matches:
{
"type": "action",
"value": "opened"
}
user - Check if sender/pusher matches:
{
"type": "user",
"value": "username"
}
repository - Check if repository matches:
{
"type": "repository",
"value": "owner/repo"
}
{{mentioned_user}} - User mentioned in comment/issue{{sender}} - Event sender email{{assignee}} - Issue/PR assignee email"admin@example.com"All the standard webhook variables are available in email subjects and bodies:
{{repo}}, {{full_repo}}, {{repo_owner}}{{branch}}, {{sender}}, {{commit}}, {{commit_msg}}{{issue_number}}, {{issue_title}}, {{issue_action}}{{comment_body}}, {{mentioned_user}}{{pr_number}}, {{pr_action}}Notify mentioned users in issue comments:
{
"name": "mention-notification",
"event": "issue_comment",
"condition": {
"type": "mention",
"value": ".*"
},
"recipients": ["{{mentioned_user}}"],
"subject": "You were mentioned in {{full_repo}}#{{issue_number}}",
"body": "Hi @{{mentioned_user}},\n\nYou were mentioned by {{sender}}:\n{{comment_body}}"
}
Notify team on push to main:
{
"name": "push-to-main",
"event": "push",
"condition": {
"type": "branch",
"value": "main"
},
"recipients": ["dev-team@example.com"],
"subject": "Push to {{full_repo}}/{{branch}}",
"body": "Pusher: {{sender}}\nCommit: {{commit}}\nMessage: {{commit_msg}}"
}
Notify assignee when issue is assigned:
{
"name": "issue-assigned",
"event": "issues",
"condition": {
"type": "action",
"value": "assigned"
},
"recipients": ["{{assignee}}"],
"subject": "Issue assigned: {{full_repo}}#{{issue_number}}",
"body": "You have been assigned to issue #{{issue_number}}: {{issue_title}}"
}
.smtp-config.json, email-rules.json) are excluded from git.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
│ ├── emailNotifier.js # Email notification callback module
│ ├── emailSender.js # SMTP email sender (zero dependencies)
│ ├── 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/ # Utility scripts
├── 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
├── .smtp-config.json.example # Example SMTP configuration
├── email-rules.json.example # Example email notification rules
├── .env # Your environment configuration (not in git)
├── commands.json # Your command configuration (not in git)
├── .smtp-config.json # Your SMTP configuration (not in git)
├── email-rules.json # Your email notification rules (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