const cp = require('child_process');
const path = require('path');
const fs = require('fs-extra');
const AWS = require('aws-sdk');
const mime = require('mime');
const downloadVersion = async (s3, s3BucketName, folder) => {
try {
const content = await s3
.getObject({
Bucket: s3BucketName,
Key: `${folder}/version.json`,
})
.promise();
return JSON.parse(content.Body.toString());
} catch (e) {
if (e.statusCode === 404) {
console.warn('远程历史版本文件不存在,创建新的远程文件!!');
return [];
} else {
throw e;
}
}
};
const upload = async (s3, localFolder, s3RootDir, s3BucketName) => {
const filesPaths = await walkSync(localFolder);
for (let i = 0; i < filesPaths.length; i++) {
const statistics = `(${i + 1}/${filesPaths.length}, ${Math.round(
((i + 1) / filesPaths.length) * 100
)}%)`;
const filePath = filesPaths[i];
const fileContent = fs.readFileSync(filePath);
// If the slash is like this "/" s3 will create a new folder, otherwise will not work properly.
const relativeToBaseFilePath = path.normalize(
path.relative(localFolder, filePath)
);
s3RootDir = s3RootDir || '';
const relativeToBaseFilePathForS3 = path
.join(s3RootDir, relativeToBaseFilePath)
.split(path.sep)
.join('/');
const mimeType = mime.getType(filePath);
console.log(`Uploading`, statistics, relativeToBaseFilePathForS3);
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
await s3
.putObject({
ACL: `public-read`,
Bucket: s3BucketName,
Key: relativeToBaseFilePathForS3,
Body: fileContent,
ContentType: mimeType,
})
.promise();
console.log(`Uploaded `, statistics, relativeToBaseFilePathForS3);
}
};
async function walkSync(dir) {
const files = fs.readdirSync(dir);
const output = [];
for (const file of files) {
const pathToFile = path.join(dir, file);
const isDirectory = fs.statSync(pathToFile).isDirectory();
if (isDirectory) {
output.push(...(await walkSync(pathToFile)));
} else {
output.push(await pathToFile);
}
}
return output;
}
module.exports = context => {
return {
fn: async () => {
console.log('is ci %s', process.env['CI']);
const config = {
s3BucketName: '',//远程桶名称
localFolder: context.outputRoot//本地编译输出目录,
accessKeyId: '',//s3 accessKeyId
secretAccessKeyId: '', //s3 secretAccessKeyId
folder: '',//桶下面的一级目录
region: '',//s3 地区
endPoint: 'https://{region}.amazonaws.com.cn',//s3 endpoint
};
AWS.config.setPromisesDependency(Promise);
const s3 = new AWS.S3({
signatureVersion: 'v4',
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKeyId,
region: config.region,
endpoint: config.endPoint,
});
//更新本地 version 文件
const versionJson = await downloadVersion(
s3,
config.s3BucketName,
config.folder
);
console.log('远程 json 文件 %o', versionJson);
const currentVersion = JSON.parse(
fs.readFileSync(path.join(context.outputRoot, 'version.json'))
)[0];
//todo 修改概率
versionJson.unshift(currentVersion);
fs.writeFileSync(
path.join(context.outputRoot, 'version.json'),
JSON.stringify(versionJson)
);
//复制一份 latest
const GitRevisionPlugin = require('git-revision-webpack-plugin');
const gitRevisionPlugin = new GitRevisionPlugin({
commithashCommand: 'rev-parse --short HEAD',
});
//需要确保必须是这次 build 出来的,否则 commit 对不上
const prefix = gitRevisionPlugin.commithash();
fs.copySync(
path.join(context.outputRoot, prefix),
path.join(context.outputRoot, 'latest')
);
//将 latest 里面指向原来 comment 的 hash 指向 latest
const command = process.env.CI
? `find ${path.join(
context.outputRoot,
'latest'
)} -type f -exec sed -i -e "s/${prefix}/latest/g" {} \\;`
: `find ${path.join(
context.outputRoot,
'latest'
)} -type f -exec sed -i '' "s/${prefix}/latest/g" {} \\;`;
console.log('exec replace with command %s', command);
cp.execSync(command);
//上传本地文件到 s3
await upload(s3, context.outputRoot, config.folder, config.s3BucketName);
console.log('发布完毕');
},
};
};