-
Notifications
You must be signed in to change notification settings - Fork 3
/
deploy-ali-oss.js
129 lines (116 loc) · 3.86 KB
/
deploy-ali-oss.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* eslint-disable no-console */
const path = require('path');
const crypto = require('crypto');
const OSS = require('ali-oss');
const fs = require('fs-extra');
const glob = require('glob');
const async = require('async');
const _ = require('lodash');
const dayjs = require('dayjs');
class DeployAliOss {
constructor(config = {}) {
const {
ossAccessKeyId,
ossAccessKeySecret,
ossBucket,
ossEndpoint,
ossTimeout,
ossNamespace,
ossPattern,
versionsRetainedNumber, // 保留的版本数量
local_target = path.resolve('dist')
} = config;
this.config.ossNamespace = ossNamespace || 'frontend';
this.config.ossPattern = ossPattern || `${local_target}/**/*.!(html)`;
this.config.versionsRetainedNumber = Math.max(versionsRetainedNumber, 1);
this.localTarget = local_target;
this.client = new OSS({
accessKeyId: ossAccessKeyId,
accessKeySecret: ossAccessKeySecret,
bucket: ossBucket,
endpoint: ossEndpoint,
timeout: ossTimeout || '600s',
});
}
config = {};
getFiles = (pattern = this.config.ossPattern) => {
return new Promise((resolve, reject) => {
glob(pattern, (err, files) => {
if (err) {
return reject(err);
}
resolve(files);
});
});
};
clearOldVersionFiles = async () => {
console.log('开始清理OSS旧版本文件...');
const { objects } = await this.client.list({
'prefix': this.config.ossNamespace,
'max-keys': 1000,
});
const objectsGroupedByName = _.groupBy(objects, (item) => {
// app.4ae2275a.js => app.js
return item.name.split('.').filter((item) => {
return !/^[0-9a-z]{8}$/.test(item);
}).join('.');
});
// 最少保留1个版本
const saveVersion = Math.max(this.versionsRetainedNumber, 1);
const deleteObjectsNames = _.flatten(
_.filter(objectsGroupedByName, list => list.length > saveVersion)
.map(list => list.sort((a, b) => dayjs(a.lastModified).diff(dayjs(b.lastModified))))
.map(list => list.slice(0, list.length - saveVersion).map(item => item.name)),
);
if (deleteObjectsNames.length) {
console.log('将从OSS删除旧版文件', deleteObjectsNames.join(','));
await this.client.deleteMulti(deleteObjectsNames);
}
console.log('清理OSS旧版本文件完成');
};
generateChecksum = async (filePath) => {
const data = await fs.readFile(filePath);
return crypto.createHash('md5').update(data).digest('hex');
};
uploadFile = async (fileName, filePath) => {
const checksum = await this.generateChecksum(filePath);
const upload = async () => {
console.log(`正在上传文件: ${filePath}`);
await this.client.put(fileName, filePath, { meta: { checksum } });
};
return this.client.head(fileName)
.then(({ meta }) => {
if (_.get(meta, 'checksum') !== checksum) {
return upload();
}
})
.catch((e) => {
if (e.status === 404) {
return upload();
}
throw e;
});
};
run = async () => {
const allFiles = await this.getFiles();
const files = allFiles.filter(item => fs.lstatSync(item).isFile());
const fileList = files.map(item => ({
filePath: item,
fileName: path.join(this.config.ossNamespace, path.relative(this.localTarget, item)),
}));
console.log('上传到OSS...');
await async.eachLimit(fileList, 10, async (item) => {
await this.uploadFile(item.fileName, item.filePath);
});
console.log('上传到OSS完成');
console.log('清理dist目录...');
await Promise.all(files.map(item => fs.remove(item)));
console.log('清理dist目录完成');
await this.clearOldVersionFiles();
};
static deploy = async (config = {}) => {
const instance = new this(config);
await instance.run();
};
}
module.exports = DeployAliOss;