在现代前端开发中,版本控制和自动化部署是提高团队效率和产品质量的关键因素。本文将介绍一个强大的脚本,它结合了版本管理、更新日志生成和自动化部署功能,为前端开发团队提供了一个完整的解决方案。
1. 概述
我们将探讨一个基于 Node.js 的脚本,它使用了 zx、semver、fs-extra 和 inquirer 等库来实现以下功能:
- 自动版本号递增
- 基于 Git 提交记录生成更新日志
- 交互式用户界面
- 自动化构建和部署
2. 技术栈
- Node.js
- zx:用于编写更易读的 shell 脚本
- semver:语义化版本控制
- fs-extra:增强的文件系统操作
- inquirer:命令行用户界面
- Git:版本控制系统
3. 脚本结构
脚本主要分为以下几个部分:
- 配置和导入
- Git 提交记录获取
- 更新日志管理
- 版本更新逻辑
- 部署流程
让我们详细探讨每个部分。
4. 配置和导入
#!/usr/bin/env zx
import semver from 'semver'
import fs from 'fs-extra'
import path from 'path'
import inquirer from 'inquirer'
import { execSync } from 'child_process'
$.verbose = true
// 定义相关信息
const serverHost = '49.232.232.209'
const username = 'root'
const remoteDir = '/www/wwwroot/zh-h5.crofys.cn'
const localDir = './dist'
const packageJsonPath = path.resolve('./package.json')
const changelogPath = path.resolve('./CHANGELOG.md')
这部分设置了脚本的基本配置,包括服务器信息、本地和远程目录路径等。使用 zx 可以让我们在 JavaScript 中更方便地执行 shell 命令。
5. Git 提交记录获取
async function getLatestGitCommits(count = 10) {
const gitLog = execSync(`git log -${count} --pretty=format:"%h %s"`, { encoding: 'utf-8' })
return gitLog.split('\n').map(line => {
const [hash, ...messageParts] = line.split(' ')
return { hash, message: messageParts.join(' ') }
})
}
这个函数使用 git log 命令获取最近的 Git 提交记录,并将其格式化为一个包含哈希和消息的对象数组。这为生成更新日志提供了基础。
6. 更新日志管理
async function getLastChangelogEntry() {
const changelog = await fs.readFile(changelogPath, 'utf8').catch(() => '')
const matches = changelog.match(/## \[\d+\.\d+\.\d+\] - \d{4}-\d{2}-\d{2}\n\n((?:- .+\n)+)/)
if (matches && matches[1]) {
return matches[1].split('\n').filter(line => line.trim()).map(line => line.replace(/^- /, ''))
}
return []
}
async function updateChangelog(version, content) {
const date = new Date().toISOString().split('T')[0]
const changelogEntry = `
## [${version}] - ${date}
${content.split('\n').map(line => `- ${line}`).join('\n')}
`
let changelog = await fs.readFile(changelogPath, 'utf8').catch(() => '')
if (!changelog.includes('# Changelog')) {
changelog = '# Changelog\n\n' + changelog
}
changelog = changelog.replace('# Changelog\n', `# Changelog\n\n${changelogEntry}\n`)
await fs.writeFile(changelogPath, changelog)
}
这两个函数负责管理 CHANGELOG.md 文件。getLastChangelogEntry 获取最后一次更新的内容,而 updateChangelog 则负责将新的更新内容添加到文件中。这确保了更新日志的一致性和可读性。
7. 版本更新逻辑
async function updateVersion() {
const packageJson = await fs.readJson(packageJsonPath)
const currentVersion = packageJson.version
const { versionType } = await inquirer.prompt({
type: 'list',
name: 'versionType',
message: '选择要升级的版本类型:',
choices: ['patch', 'minor', 'major']
})
const newVersion = semver.inc(currentVersion, versionType)
// ... 省略部分代码 ...
const lastChangelogEntries = await getLastChangelogEntry()
const recentCommits = await getLatestGitCommits()
const newCommits = recentCommits.filter(commit =>
!lastChangelogEntries.some(entry => entry.includes(commit.message))
)
const { selectedCommits } = await inquirer.prompt({
type: 'checkbox',
name: 'selectedCommits',
message: '选择要包含在更新日志中的提交:',
choices: newCommits.map(commit => ({
name: `${commit.hash.slice(0, 7)} ${commit.message}`,
value: commit.message
}))
})
const updateContent = selectedCommits.join('\n')
packageJson.version = newVersion
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 })
await updateChangelog(newVersion, updateContent)
console.log(`版本号已更新: ${currentVersion} -> ${newVersion}`)
return newVersion
}
这个函数是脚本的核心,它处理版本更新的整个流程:
- 读取当前版本号
- 让用户选择要升级的版本类型(patch、minor 或 major)
- 计算新的版本号
- 获取最近的 Git 提交记录
- 过滤出新的提交(不在上一次更新日志中的提交)
- 让用户选择要包含在新的更新日志中的提交
- 更新 package.json 中的版本号
- 更新 CHANGELOG.md 文件
这个过程既自动化了版本控制,又保留了人工干预的灵活性,确保了版本更新的准确性和相关性。
8. 部署流程
async function deployToRemote() {
console.log('开始部署...')
const newVersion = await updateVersion()
await $`npm run build`
if (!await fs.pathExists(localDir)) {
console.error('错误: 本地 dist 目录不存在!')
process.exit(1)
}
console.log('清除远程目录...')
await $`ssh ${username}@${serverHost} "rm -rf ${remoteDir}/*"`
console.log('确保远程目录存在...')
await $`ssh ${username}@${serverHost} "mkdir -p ${remoteDir}"`
console.log('上传文件到远程服务器...')
await $`scp -r ${localDir}/* ${username}@${serverHost}:${remoteDir}`
console.log('创建版本文件...')
await $`ssh ${username}@${serverHost} "echo ${newVersion} > ${remoteDir}/version.txt"`
console.log(`部署完成!新版本: ${newVersion}`)
}
deployToRemote().catch(err => {
console.error('部署过程中发生错误:', err)
process.exit(1)
})
部署函数 deployToRemote 执行以下步骤:
- 更新版本
- 构建项目
- 清理远程目录
- 上传新的构建文件
- 在远程服务器上创建版本文件
这个过程自动化了整个部署流程,大大减少了人为错误的可能性。
9. 最佳实践和注意事项
- 安全性:确保服务器访问凭证得到妥善保护,不要在代码中硬编码敏感信息。
- 错误处理:脚本包含了基本的错误处理,但在生产环境中可能需要更健壮的错误处理机制。
- 配置管理:考虑使用配置文件来管理服务器信息和其他可变参数,以增加灵活性。
- 持续集成:这个脚本可以很容易地集成到 CI/CD 管道中,进一步自动化开发流程。
10. 结论
这个脚本为前端开发团队提供了一个强大的工具,自动化了版本控制、更新日志生成和部署过程。通过结合 Git 操作、语义化版本控制和交互式命令行界面,它不仅提高了效率,还确保了版本管理的一致性和准确性。
随着项目的发展,可以进一步扩展这个脚本,例如添加自动化测试、性能检查或者与项目管理工具的集成。持续改进这样的自动化工具,将极大地提升团队的生产力和产品质量。
需要全部代码私信我