node.js - 用于克隆 Bitbbuket 存储库并推送到 s3 的 Nodejs-Lambda 函数
问题描述
每当将提交推送到 SCM(使用 webhooks--->APi 网关触发 lambda)以克隆 BitBucket-server 存储库并将其作为 zip 文件推送到 s3 存储桶时,我都使用下面的 node.js 代码运行 lambda 函数,成功克隆存储库时 lambda 函数超时。我正在使用从 apigateway 传递的事件/json 正文。
const axios = require('axios');
const s3 = new AWS.S3();
const crypto = require('crypto');
exports.handler = async (event) => {
console.log(`Incoming event: ${JSON.stringify(event)}`);
const eventBody = JSON.parse(event.body);
const normalizedHeaders = normalizeObject(event.headers);
if ('x-event-key' in normalizedHeaders && normalizedHeaders['x-event-key'] === 'diagnostics:ping') {
return responseToApiGw(200, 'Webhook configured successfully');
}
if (!(checkSignature(process.env.BITBUCKET_SECRET, normalizedHeaders['x-hub-signature'], event.body))) {
console.log('Invalid webhook message signature');
return responseToApiGw(401, 'Signature is not valid');
}
console.log('Signature validated successfully');
if (!(eventBody.changes[0].ref.type === 'BRANCH')) {
console.log('Invalid event type');
throw new Error('Invalid event type');
}
const repoConfig = {
serverUrl: process.env.BITBUCKET_SERVER_URL,
projectName: eventBody.repository.project.key,
repoName: eventBody.repository.name,
branch: eventBody.changes[0].ref.displayId,
token: process.env.BITBUCKET_TOKEN
};
const file = await downloadFile(repoConfig);
console.log(file);
const s3Upload = await s3.upload({
Bucket: process.env.S3BUCKET,
ServerSideEncryption: 'AES256',
Key: `${repoConfig.projectName}/${repoConfig.repoName}/${repoConfig.branch}.zip`,
Body: file
}).promise();
console.log(s3Upload);
console.log('Exiting successfully');
return responseToApiGw(200, 'success');
};
function normalizeObject(inputObject) {
console.log('info', '>>> normalizeObject()');
const requestKeys = Object.keys(inputObject);
let outputObject = {};
for (let i = 0; i < requestKeys.length; i++) {
outputObject[requestKeys[i].toLowerCase()] = inputObject[requestKeys[i]];
}
console.log('info', '<<< normalizeObject()');
return outputObject;
}
async function downloadFile(repoConfig) {
console.log('info', '>>> downloadFile()');
const params = {
method: 'get',
baseURL: repoConfig.serverUrl,
url: `/rest/api/latest/projects/${repoConfig.projectName}/repos/${repoConfig.repoName}/archive?at=refs/heads/${repoConfig.branch}&format=zip`,
responseType: 'stream',
headers: {
Authorization: `Bearer ${repoConfig.token}`
}
};
try {
const resp = await axios.request(params);
console.log('info', '<<< downloadFile()');
return resp.data;
}
catch (err) {
console.log('error', err);
throw new Error(err);
}
}
function checkSignature(signingSecret, signature, body) {
console.log('info', '>>> signingSecret()');
const hash = crypto.createHmac('sha256', signingSecret).update(body).digest('hex');
const signatureHash = signature.split('=');
if (signatureHash[1] === hash) {
console.log('info', '<<< signingSecret()');
return true;
}
console.log('info', '<<< signingSecret()');
return false;
}
function responseToApiGw(statusCode, detail) {
if (!statusCode) {
throw new TypeError('responseToApiGw() expects at least argument statusCode');
}
if (statusCode !== '200' && !detail) {
throw new TypeError('responseToApiGw() expects at least arguments statusCode and detail');
}
let body = {};
if (statusCode === '200' && detail) {
body = {
statusCode: statusCode,
message: detail
};
} else if (statusCode === '200' && !detail) {
body = {
statusCode: statusCode
};
} else {
body = {
statusCode: statusCode,
fault: detail
};
}
let response = {
statusCode: statusCode,
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
}
};
return response;
}```
解决方案
推荐阅读
- reactjs - 更改状态后,React 组件不会重新渲染
- javascript - VueJS | 如何在 vue.js 中获取 url 参数?
- python - 从 Django 数据库中检索超过当前时间的日期
- android - 当“npx react-native run-android”时,React-Native 没有这样的 AndroidManifest.xml
- java - 使用 Mockito 进行 Spring Boot JmsTemplate Junit 测试
- php - 如何在 laravel eloquent 中显示每个类别的视频
- flutter - AnimationController 未定义命名参数“vsync”
- sql - 将 3 维表存储在数据库中,其中 1 维随时间增加
- html - 可滚动内容溢出
- java - 如何在没有root的情况下在android中修剪整个设备的/缓存?