-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrelease.js
251 lines (232 loc) · 6.73 KB
/
release.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// 本文件是构建脚本,用于生成 package.nw.zip 和 app.nw.zip
import fs from "fs-extra";
import path from "path";
import archiver from "archiver";
import { fileURLToPath } from "url";
import { execSync } from "child_process";
import { currentVersion } from "./src/assets/versionTips.js";
import chalk from "chalk";
// 获取当前文件目录的绝对路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const distDir = path.join(__dirname, "dist");
const packageNwDir = path.resolve(__dirname, "nw-folders/unzipped/package.nw");
const appNwDir = path.join(__dirname, "nw-folders/unzipped/app.nw");
const outputDir = path.join(__dirname, "nw-folders/zipped");
let releaseArg = '--latest'
// 执行 shell 命令
function execCommand(command) {
try {
console.log(chalk.blue(`EXEC: ${command}`));
const output = execSync(command, { encoding: "utf-8" });
return output;
} catch (error) {
console.error(
chalk.red("Error executing command:"),
chalk.red(error.message)
);
process.exit(1);
}
}
/**
*
* @param {*} version
* @returns
*/
const npmRunBuild = async()=>{
try{
execCommand(`npm run build`)
}
catch(error){
console.error(chalk.red("Error running npm run build:"), chalk.red(error));
}
}
// 获取上一个tag
function getPreviousTag(version) {
try {
const result = execCommand(`git tag --sort=-creatordate`).split("\n");
let prevTag = "";
for (let i = 0; i < result.length; i++) {
if (result[i] === version) {
prevTag = result[i + 1] || "";
break;
}
}
return prevTag;
} catch (error) {
console.error(
chalk.red("Error getting previous tag:"),
chalk.red(error)
);
return "";
}
}
// 获取标签之间的提交信息
function getCommitNotes(fromTag, toTag) {
try {
// 获取标签之间的提交信息
const commits = execCommand(`git log ${fromTag}..${toTag} --oneline`);
// 使用正则表达式删除哈希值(如63926d4),并保持换行
const commitNotes =
"**--- " +
commits
.replace(/^[a-f0-9]{7}\s+/gm, "") // 删除每行开头的哈希值
.trim() // 去掉首尾空格(不去掉中间换行符)
.replace(/\n/g, "<br/>--- ") +
"**";
return commitNotes; // 返回格式化后的提交日志
} catch (error) {
console.error(
chalk.red("Error getting commit notes:"),
chalk.red(error)
);
return "";
}
}
// 先确保 outputDir 目录存在,如果不存在则创建它
async function ensureOutputDir() {
try {
await fs.ensureDir(outputDir);
console.log(`Output directory is ready: ${outputDir}`);
} catch (error) {
console.error(
chalk.red(`Failed to create output directory: ${outputDir}`),
chalk.red(error)
);
}
}
// 复制文件
async function copyFiles(srcDir, destDir) {
try {
await fs.ensureDir(destDir);
await fs.copy(srcDir, destDir, { overwrite: true });
console.log(`Files copied from ${srcDir} to ${destDir}`);
} catch (error) {
console.error(
chalk.red(`Failed to copy files from ${srcDir} to ${destDir}:`),
chalk.red(error)
);
}
}
// 压缩文件夹
async function zipFolder(folderPath, zipPath) {
try {
const output = fs.createWriteStream(zipPath);
const archive = archiver("zip", { zlib: { level: 9 } });
output.on("close", () => {
console.log(
`${zipPath} has been created (${archive.pointer()} bytes)`
);
});
archive.on("error", (err) => {
throw err;
});
archive.pipe(output);
archive.directory(folderPath, path.basename(folderPath));
await archive.finalize();
} catch (error) {
console.error(
chalk.red(`Failed to create zip for ${folderPath}:`),
chalk.red(error)
);
}
}
// 检查 GitHub Release 是否存在
function checkReleaseExists(version) {
try {
const result = execCommand(
`gh release list --limit 1000 --json tagName`
);
return result.includes(version); // 如果版本号在列表中,表示已经存在该 Release
} catch (error) {
console.error(
chalk.red("Failed to check for existing release:"),
chalk.red(error)
);
return false;
}
}
// 发布或更新 GitHub Release
async function publishRelease() {
// 检查是否已存在该版本的 Release
const releaseExists = checkReleaseExists(currentVersion);
// 获取上一个标签
const previousTag = getPreviousTag(currentVersion);
console.log(`find previousTag ${previousTag}`);
// 获取上一个标签到当前标签的提交信息
let commitNotes = "";
if (previousTag) {
commitNotes = getCommitNotes(previousTag, currentVersion);
}
if (releaseExists) {
console.log(`Release ${currentVersion} already exists. Delete it...`);
execCommand(`gh release delete ${currentVersion} --yes`);
console.log(`Release ${currentVersion} has been deleted.`);
}
console.log(`Creating a new release...`);
// 创建新的 Release 并上传文件
execCommand(
`gh release create ${currentVersion} ${outputDir}/package.nw.zip ${outputDir}/app.nw.zip --title "${currentVersion}" ${releaseArg} --notes "${commitNotes}"`
);
console.log(`Release ${currentVersion} has been created.`);
}
const args = process.argv.slice(2)
const flags = {
'--help':{
state:false,
method:()=>{
console.log('Usage: node release.js [options]')
console.log('Default function: ',chalk.yellow('build and zip, then publish a latest release'))
console.log('Options:')
Object.keys(flags).forEach((key)=>{
console.log(chalk.yellow(`\t${key}`),`: ${flags[key].help}`);
})
},
help:'show this help message'
},
'--no-build':{
state: true,
method: npmRunBuild,
help:'skip npm run build'
},
'--draft':{
state: false,
method:()=>{
releaseArg = '--draft'
},
help:'create a draft release, instead of a latest release'
}
}
function checkFlags() {
if(args.length === 0){
console.log('No args passed, run:\n\tnpm run build\n\tcopy && zip\n\tpublish release')
return
}
if(args.indexOf('--help') !== -1){
flags['--help'].method()
process.exit(0)
}
console.log('Valid flags passed:')
args.forEach((arg) => {
if(flags[arg]){
flags[arg].state = !flags[arg].state
console.log(`\t${arg}`)
}
})
}
(async () => {
checkFlags()
Object.keys(flags).forEach((key) => {
if(flags[key].state){
flags[key].method()
}
})
await copyFiles(distDir, packageNwDir);
await copyFiles(distDir, appNwDir);
await ensureOutputDir();
// 压缩 package.nw 和 app.nw 文件夹
await zipFolder(packageNwDir, path.join(outputDir, "package.nw.zip"));
await zipFolder(appNwDir, path.join(outputDir, "app.nw.zip"));
await publishRelease();
console.log(chalk.green("Release success!"));
})();