deployment methods - new and docs
This commit is contained in:
137
_deploy/webhook-receiver.js
Normal file
137
_deploy/webhook-receiver.js
Normal file
@ -0,0 +1,137 @@
|
||||
// Webhook receiver for Gitea push events
|
||||
// This service listens for webhook events from Gitea and triggers a deployment
|
||||
// when changes are pushed to the monitored branches
|
||||
|
||||
const express = require('express');
|
||||
const http = require('http');
|
||||
const crypto = require('crypto');
|
||||
const { exec } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Configuration (can be moved to environment variables)
|
||||
const config = {
|
||||
port: process.env.WEBHOOK_PORT || 9000,
|
||||
secret: process.env.WEBHOOK_SECRET || 'change-this-secret-in-production',
|
||||
deployScript: process.env.DEPLOY_SCRIPT || path.join(__dirname, 'webhook-deploy.sh'),
|
||||
logFile: process.env.LOG_FILE || path.join(__dirname, '../logs/webhook.log'),
|
||||
allowedBranches: (process.env.ALLOWED_BRANCHES || 'main,master').split(','),
|
||||
allowedRepositories: (process.env.ALLOWED_REPOSITORIES || 'mwhitnessing').split(',')
|
||||
};
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
const logsDir = path.dirname(config.logFile);
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create Express app
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Helper function to log messages
|
||||
function log(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `[${timestamp}] ${message}\n`;
|
||||
console.log(logMessage.trim());
|
||||
fs.appendFileSync(config.logFile, logMessage);
|
||||
}
|
||||
|
||||
// Verify Gitea webhook signature
|
||||
function verifySignature(req) {
|
||||
const signature = req.headers['x-gitea-signature'];
|
||||
if (!signature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hmac = crypto.createHmac('sha256', config.secret);
|
||||
const computedSignature = hmac.update(JSON.stringify(req.body)).digest('hex');
|
||||
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(signature),
|
||||
Buffer.from(computedSignature)
|
||||
);
|
||||
}
|
||||
|
||||
// Handle Gitea push webhook
|
||||
app.post('/webhook', (req, res) => {
|
||||
// Log receipt of webhook
|
||||
log('Received webhook request');
|
||||
|
||||
try {
|
||||
// Check if webhook signature is valid
|
||||
if (!verifySignature(req)) {
|
||||
log('Invalid webhook signature');
|
||||
return res.status(403).send('Invalid signature');
|
||||
}
|
||||
|
||||
// Extract relevant information from the webhook payload
|
||||
const { ref, repository } = req.body;
|
||||
|
||||
// Check if this is a branch we care about
|
||||
const branchName = ref.replace('refs/heads/', '');
|
||||
if (!config.allowedBranches.includes(branchName)) {
|
||||
log(`Ignoring push to branch: ${branchName}`);
|
||||
return res.status(200).send('Ignored branch');
|
||||
}
|
||||
|
||||
// Check if this is a repository we care about
|
||||
const repoName = repository.name;
|
||||
if (!config.allowedRepositories.includes(repoName)) {
|
||||
log(`Ignoring push to repository: ${repoName}`);
|
||||
return res.status(200).send('Ignored repository');
|
||||
}
|
||||
|
||||
// Log the event
|
||||
log(`Received push event for ${repoName}/${branchName}`);
|
||||
|
||||
// Respond to webhook immediately
|
||||
res.status(200).send('Processing deployment');
|
||||
|
||||
// Execute the deployment script with the branch name
|
||||
const command = `${config.deployScript} ${branchName}`;
|
||||
log(`Executing: ${command}`);
|
||||
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
log(`Deployment error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
log(`Deployment stderr: ${stderr}`);
|
||||
}
|
||||
log(`Deployment stdout: ${stdout}`);
|
||||
log('Deployment completed successfully');
|
||||
});
|
||||
} catch (error) {
|
||||
log(`Error processing webhook: ${error.message}`);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).send('Error processing webhook');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Start the server
|
||||
const server = http.createServer(app);
|
||||
server.listen(config.port, () => {
|
||||
log(`Webhook receiver listening on port ${config.port}`);
|
||||
log(`Monitoring branches: ${config.allowedBranches.join(', ')}`);
|
||||
log(`Monitoring repositories: ${config.allowedRepositories.join(', ')}`);
|
||||
});
|
||||
|
||||
// Handle server shutdown
|
||||
process.on('SIGTERM', () => {
|
||||
log('Shutting down webhook receiver...');
|
||||
server.close(() => {
|
||||
log('Webhook receiver stopped');
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
log('Shutting down webhook receiver...');
|
||||
server.close(() => {
|
||||
log('Webhook receiver stopped');
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user