第一章 本周导学


1-1 本周整体介绍和学习方法

  • GitFlow实战
  • 通过simple-git操作git命令
  • Github和Gitee openAPI接入
  • 本周加餐:Node最佳实践分享

主要内容
  • Git仓库初始化(利用Github和Gitee OpenAPI)
  • 本地Git初始化
  • GitFlow流程实现(代码自动提交)

附赠内容

Node项目最佳实践:

  • 项目结构最佳实践
  • 异常处理最佳实践
  • 测试最佳实践
  • 发布上线最佳实践
  • 安全最佳实践

第二章 Git Flow 模块架构设计


2-1 GitFlow模块架构设计

点击查看【processon】

2-2 GitFlow流程回顾

点击查看【processon】

第三章 Github&Gitee API 接入


3-1 创建Git类

  1. 首先创建一个新的package—git,用来管理与git相关的所有内容
  • lerna create git models/git
  1. 在上周代码写完this.prepare()之后(commands/publish/lib/index.js中),我们就需要去调用这个新建的git包,实例化出来一个对象,并将projectInfo的信息传递进去
  • const Git = require(‘@cloudscope-cli/git’)
  • const git = new Git()
  1. 我们在新建的 models/git/lib/index.js中新建一个Git类,本节代码内容为:
  1. 'use strict';
  2. const SimpleGit = require('simple-git')
  3. class Git {
  4. constructor({name, version, dir}){
  5. this.name = name
  6. this.version = version
  7. this.dir = dir
  8. this.git = SimpleGit(dir)
  9. this.gitServer = null
  10. }
  11. prepare(){
  12. }
  13. init(){
  14. console.log('Git init')
  15. }
  16. }
  17. module.exports = Git;

3-2 用户主目录检查逻辑开发

本节的主要代码为在Class Git中编写prepare方法,检查用户主目录是否存在

  1. 'use strict';
  2. const path = require('path')
  3. const fs = require('fs')
  4. const SimpleGit = require('simple-git')
  5. const userHome = require('user-home')
  6. const log = require('@cloudscope-cli/log')
  7. const fse = require('fs-extra')
  8. const DEFAULT_CLI_HOME = '.cloudscope-cli'
  9. class Git {
  10. constructor({name, version, dir}){
  11. this.name = name
  12. this.version = version
  13. this.dir = dir
  14. this.git = SimpleGit(dir)
  15. this.gitServer = null
  16. this.homePath = null
  17. }
  18. async prepare(){
  19. this.checkHomePath();// 检查缓存主目录
  20. }
  21. checkHomePath(){
  22. if(!this.homePath){
  23. if(process.env.CLI_HOME_PATH){
  24. this.homePath = process.env.CLI_HOME_PATH
  25. }else{
  26. this.homePath = path.resolve(userHome,DEFAULT_CLI_HOME)
  27. }
  28. }
  29. log.verbose('home:',this.homePath )
  30. fse.ensureDirSync(this.homePath);
  31. if(!fs.existsSync(this.homePath)){
  32. throw new Error('用户主目录获取失败!')
  33. }
  34. }
  35. init(){
  36. console.log('Git init')
  37. }
  38. }
  39. module.exports = Git;

本节对path/fs/user-home/fs-extra进行简单回顾。

  • path:node内置,path模块提供了处理文件和目录的路径的实用工具。
    • path.dirname(path) ,返回something(文件或文件夹)所在的文件目录。
    • path.extname(path):返回最后一次出现.字符到字符串的结尾
    • path.isAbsolute(path):确定这个path路径是否为绝对路径。
    • path.join([…paths]):路径拼接
    • path.parse(path):将路径返回成一个对象{root,dir,name,ext,base}
    • path.resolve(path):将路径或路径片段的序列解析为绝对路径,给定的路径序列从右向左处理
    • path.seq:window上是\,Mac上是/
  • fs:node内置,文件系统
    • fs.existsSync(path):如果路径存在返回true,不存在返回false
  • user-home\fs-extra:第三方

3-3 选择远程Git仓库逻辑开发

  • 上一节的内容总结一句大白话就是:获取 /User/username/.cloudscope-cli目录,如果没有就创建。
  • 本节的内容一句话总结就是实现了一个checkGitServer方法,这个方法的主要功能是检查在上文提到的.cloudscope-cli下是否有.git/.git-server文件,没有的话通过 inquirer询问创建
  • 且在 @cloudscope-cli/utils下新建了 readFile和writeFile方法
  • 并且添加了一个参数:refreshServer,如果有这个参数就判断是否重写.git-server文件

本节新开发添加代码如下:

  1. const { readFile,writeFile } = require('@cloudscope-cli/utils')
  2. const inquirer = require('inquirer')
  3. const DEFAULT_CLI_HOME = '.cloudscope-cli'
  4. const GIT_ROOT_DIR = '.git'
  5. const GIT_SERVER_FILE = '.git_server'
  6. const GITHUB = 'github'
  7. const GITEE ='gitee'
  8. const GIT_SERVER_TYPE = [{
  9. name:'Github',
  10. value: GITHUB
  11. },{
  12. name: 'Gitee',
  13. value: GITEE
  14. }]
  15. async prepare(){
  16. this.checkHomePath();// 检查缓存主目录
  17. await this.checkGitServer();//检查用户远程仓库类型
  18. }
  19. async checkGitServer(){
  20. const gitServerPath = this.createPath(GIT_SERVER_FILE)
  21. let gitServer = readFile(gitServerPath)
  22. if(!gitServer){ // 如果没有读取到.git-server文件中的内容
  23. gitServer = await this.choiceServer(gitServerPath)
  24. log.success('git server 写入成功',`${gitServer} -> ${gitServerPath}`)
  25. }else{ // 如果读取到了 内容
  26. if(this.refreshServer){ // 是否重写标识
  27. const refresh = (await inquirer.prompt([{
  28. type:'confirm',
  29. name:'ifContinue',
  30. default:false,
  31. message:'当前.git-server目录已存在,是否要重写选择托管平台?'
  32. }])).ifContinue
  33. if(refresh){
  34. gitServer = await this.choiceServer(gitServerPath)
  35. log.success('git server 重写成功',`${gitServer} -> ${gitServerPath}`)
  36. }else{
  37. log.success('git server 获取成功 ', gitServer)
  38. }
  39. }else{ //不重写,直接读取
  40. log.success('git server 获取成功 ', gitServer)
  41. }
  42. }
  43. this.gitServer = this.createServer(gitServer)
  44. }
  45. async choiceServer(gitServerPath){
  46. const gitServer = (await inquirer.prompt({
  47. type:'list',
  48. name:'server',
  49. message:'请选择你想要托管的Git平台',
  50. default: GITHUB,
  51. choices:GIT_SERVER_TYPE
  52. })).server;
  53. writeFile(gitServerPath,gitServer)
  54. return gitServer
  55. }
  56. createPath(file){
  57. const rootDir = path.resolve(this.homePath,GIT_ROOT_DIR)
  58. const serverDir = path.resolve(rootDir,file)
  59. fse.ensureDirSync(rootDir)
  60. return serverDir
  61. }

@cloudscope-cli/utils 下的readFile和writeFile方法实现为使用node自带的fs.readFileSync(path)和fs.writeFileSync(path)方法

3-4 创建GitServer类

本节主要创建了一个GitServer类,并新建Github类和Gitee类分别继承GitServer。

  1. function error(methodName) {
  2. throw new Error(`${methodName} must be implemented!` )
  3. }
  4. class GitServer {
  5. constructor(type,token){
  6. this.type= type
  7. this.token = token
  8. }
  9. setToken(){
  10. error('setToken')
  11. }
  12. createRepo(){
  13. error('createRepo')
  14. }
  15. createOrgRepo(){
  16. error('createOrgRepo')
  17. }
  18. getRemote(){
  19. error('getRemote')
  20. }
  21. getuser(){
  22. error('getuser')
  23. }
  24. getOrg(){
  25. error('getOrg')
  26. }
  27. }
  28. module.exports = GitServer

3-5 生成远程仓库Token逻辑开发

本节课的主要内容为生成远程仓库Token。

  • 首先在类Github.js和Gitee.js中分别实现获取帮助文档和相应token的文档方法
  1. //Github.js
  2. getSSHKeysUrl(){
  3. return 'https://gitee.com/profile/sshkeys';
  4. }
  5. //Gitee.js
  6. getSSHKeysUrl(){
  7. return 'https://gitee.com/profile/sshkeys';
  8. }
  9. getTokenHelpUrl(){
  10. return 'https://gitee.com/help/articles/4191'
  11. }

然后在models/git/index.js中实现获取Giteetoken的方法

  • 安装了 terminal-link库,且版本号为2.1.1,功能是直接在ternimal中点击跳转链接
  1. const terminalLink = require('terminal-link')
  2. const GIT_TOKEN_FILE = '.git_token'
  3. async checkGitToken(){
  4. const tokenPath = this.createPath(GIT_TOKEN_FILE)
  5. let token = readFile(tokenPath)
  6. if(!token || this.refreshServer){
  7. log.warn(this.gitServer.type + ' token未生成,请先生成!' + this.gitServer.type + ' token,'+terminalLink('链接',this.gitServer.getTokenHelpUrl())) ;
  8. token = (await inquirer.prompt({
  9. type:'password',
  10. name:'token',
  11. message:'请将token复制到这里',
  12. default:'',
  13. })).token
  14. writeFile(tokenPath,token)
  15. log.success('token 写入成功',` ${tokenPath}`)
  16. }else{
  17. log.success('token获取成功',tokenPath)
  18. }
  19. this.token = token
  20. this.gitServer.setToken(token)
  21. }

3-6 Gitee API接入+获取用户组织信息功能开发

本章节主要是Gitee API的接入:获取用户信息和组织信息

  • 使用第三方库有 axios
  • 新建的文件有 GitServerRequest.js
  1. const axios = require('axios')
  2. const BASE_URL = 'https://gitee.com/api/v5'
  3. class GiteeRequest {
  4. constructor(token){
  5. this.token = token
  6. this.service = axios.create({
  7. baseURL:BASE_URL,
  8. timeout:5000
  9. })
  10. this.service.interceptors.response.use(
  11. response =>{
  12. return response.data
  13. },
  14. error =>{
  15. if(error.response && error.response.data){
  16. return error.response
  17. } else {
  18. return Promise.reject(error)
  19. }
  20. }
  21. )
  22. }
  23. get(url,params,headers){
  24. return this.service({
  25. url,
  26. params:{
  27. ...params,
  28. access_token:this.token
  29. },
  30. method:'get',
  31. headers,
  32. })
  33. }
  34. }
  35. module.exports = GiteeRequest

index.js主代码主要实现的方法是getUserAndOrgs:

  1. async getUserAndOrgs(){
  2. this.user = await this.gitServer.getUser()
  3. if(!this.user){
  4. throw new Error('用户信息获取失败')
  5. }
  6. this.orgs = await this.gitServer.getOrg(this.user.login)
  7. if(!this.orgs){
  8. throw new Error('组织信息获取失败')
  9. }
  10. log.success(this.gitServer.type + ' 用户和组织信息获取成功')
  11. }

3-7 Github API接入开发

本节代码类似于Gitee API,不同点在于,Github API需要在headers中传入token:config.headers[‘Authorization’] =token ${**this**.token} 然后,基础BASE_URL更换,获取组织URL更换,改动部分代码即可。

3-8 远程仓库类型选择逻辑开发

之前的章节我们选择了Git托管类型,生成了相关托管平台的token,获取到了个人和组织的信息,然后这节我们将要继续选择:确认远程仓库的类型(是个人还是组织),如果我们拿到的信息只有个人,那么就不显示组织选项。 同样,我们要将拿到的个人或者组织登录名(login)以及类型(owner)写入到缓存文件中.

  1. const GIT_OWN_FILE = '.git_own'
  2. const GIT_LOGIN_FILE = '.git_login'
  3. const REPO_OWNER_USER = 'user'
  4. const REPO_OWNER_ORG = 'org'
  5. const GIT_OWNER_TYPE = [{
  6. name:'个人',
  7. value: REPO_OWNER_USER
  8. },{
  9. name: '组织',
  10. value: REPO_OWNER_ORG
  11. }]
  12. const GIT_OWNER_TYPE_ONLY = [{
  13. name:'个人',
  14. value: REPO_OWNER_USER
  15. }]
  16. ………………
  17. await this.checkGitOwner();//确认远程仓库类型
  18. ………………
  19. async checkGitOwner(){
  20. const ownerPath =this.createPath(GIT_OWN_FILE) ;
  21. const loginPath =this.createPath(GIT_LOGIN_FILE) ;
  22. let owner = readFile(ownerPath)
  23. let login = readFile(loginPath)
  24. if(!owner || !login || this.refreshOwner){
  25. owner = (await inquirer.prompt({
  26. type:'list',
  27. name:'owner',
  28. message:'请选择远程仓库类型',
  29. default: REPO_OWNER_USER,
  30. choices:this.orgs.length > 0 ? GIT_OWNER_TYPE : GIT_OWNER_TYPE_ONLY
  31. })).owner
  32. if(owner === REPO_OWNER_USER){
  33. login = this.user.login
  34. }else{
  35. login = (await inquirer.prompt({
  36. type:'list',
  37. name:'login',
  38. message:'请选择',
  39. choices:this.orgs.map(item =>({
  40. name:item.login,
  41. value: item.login,
  42. }))
  43. })).login
  44. }
  45. writeFile(ownerPath,owner)
  46. writeFile(loginPath,login)
  47. log.success('owner 写入成功',`${owner} -> ${ownerPath}`)
  48. log.success('login 写入成功',`${login} -> ${loginPath}`)
  49. }else{
  50. log.success('owner 读取成功',`${owner} -> ${ownerPath}`)
  51. log.success('login 读取成功',`${login} -> ${loginPath}`)
  52. }
  53. this.owner = owner
  54. this.login = login
  55. }

第四章 GitFlow 初始化流程开发


4-1 Gitee获取和创建仓库API接入

  • 这节的代码,出了一个小bug,调试到了天亮,bug方法的实现为下面示例50行:this.handleResponse(response),课程代码讲到在获取一个仓库的API时没有status参数,经测试是有的。
  • 本节主要完成的功能有:
    • 检查并创建远程仓库 checkRepo 方法实现
    • GiteeRequest添加post请求
    • Gitee类实现 createRepo()getRepo() 方法
  1. await this.checkRepo(); // 检查并创建远程仓库
  2. //models/git/lib/index.js
  3. async checkRepo(){
  4. let repo = await this.gitServer.getRepo(this.login,this.name)
  5. log.verbose('repo',repo)
  6. if(!repo){ //如果远程仓库不存在,就去创建
  7. let spinner = spinnerStart('开始创建远程仓库')
  8. try {
  9. if(this.owner === REPO_OWNER_USER){
  10. repo = await this.gitServer.createRepo(this.name)
  11. log.success('用户个人远程仓库创建成功!')
  12. }else{
  13. this.gitServer.createOrgRepo(this.name,this.login)
  14. log.success('用户组织远程仓库创建成功1')
  15. }
  16. } catch (error) {
  17. log.error(error)
  18. }finally {
  19. spinner.stop(true)
  20. }
  21. if(!repo){
  22. throw new Error('远程仓库创建失败')
  23. }
  24. }else{
  25. log.success('远程仓库已存在且获取成功!')
  26. }
  27. this.repo = repo
  28. }
  29. //models/git/lib/GiteeRequest.js
  30. post(url,data,headers){
  31. return this.service({
  32. url,
  33. params:{
  34. access_token:this.token,
  35. },
  36. data,
  37. method:'POST',
  38. headers
  39. })
  40. }
  41. //models/git/lib/Gitee.js
  42. getRepo(login,name){
  43. //GET https://gitee.com/api/v5/repos/{owner}/{repo}
  44. return this.request
  45. .get(`/repos/${login}/${name}`)
  46. .then(response =>{
  47. return this.handleResponse(response)
  48. })
  49. }
  50. createRepo(name){
  51. // POST https://gitee.com/api/v5/user/repos
  52. return this.request.post('/user/repos',{
  53. name,
  54. })
  55. }

4-2 Github获取和创建仓库API接入

与Gitee获取和创建仓库API类似。GithubRequest同样实现了post方法。 类Github同样实现了getRepo和createRepo方法。

4-3 Github&Gitee组织仓库创建API接入

本节内容较为简单,实现了远程创建组织仓库API

  1. createOrgRepo(name,login){
  2. return this.request.post(`/orgs/${login}/repos`,{
  3. name
  4. },{
  5. accept:'application/vnd.github.v3+json'
  6. })

4-4 gitignore文件检查

提交准备工作:有些项目没有默认创建.gitignore,因此会引发提交大量无用或无关代码。 因此,我们需要检查并创建.gitignore文件的方法 这里需要注意的是安装的.gitignore安装目录为当前执行文件,而不是缓存文件

  1. const GIT_IGNORE_FILE='.gitignore'
  2. this.checkGitIgnore();//检查并创建.gitignore文件
  3. checkGitIgnore(){
  4. const gitIgnorePath = path.resolve(this.dir,GIT_IGNORE_FILE)
  5. console.log(gitIgnorePath)
  6. if(!fs.existsSync(gitIgnorePath)){
  7. writeFile(gitIgnorePath,`.DS_Store
  8. node_modules
  9. /dist
  10. # local env files
  11. .env.local
  12. .env.*.local
  13. # Log files
  14. npm-debug.log*
  15. yarn-debug.log*
  16. yarn-error.log*
  17. pnpm-debug.log*
  18. # Editor directories and files
  19. .idea
  20. .vscode
  21. *.suo
  22. *.ntvs*
  23. *.njsproj
  24. *.sln
  25. *.sw?
  26. `)
  27. log.success(`自动写入${GIT_IGNORE_FILE}文件成功!`)
  28. }
  29. }

4-5 git本地仓库初始化和远程仓库绑定

本节主要完成的功能为本地的仓库的初始化:即执行git init方法和git addRemote方法。

  1. await this.init(); //完成本地仓库初始化
  2. async init(){
  3. if(await this.getRemote()){
  4. return
  5. }
  6. await this.initAndAddRemote();
  7. }
  8. async initAndAddRemote(){
  9. log.info('执行git初始化')
  10. await this.git.init(this.dir)
  11. log.info('添加git remote')
  12. const remotes = await this.git.getRemotes();
  13. console.log('git remotes',remotes)
  14. if(!remotes.find(item => item.name === 'origin')){
  15. await this.git.addRemote('origin',this.remote)
  16. }
  17. }
  18. async getRemote(){
  19. const gitPath = path.resolve(this.dir,GIT_ROOT_DIR)
  20. this.remote = this.gitServer.getRemote(this.login,this.name)
  21. if(fs.existsSync(gitPath)){
  22. log.success('git已完成初始化')
  23. return true
  24. }
  25. }

4-6 git自动化提交功能开发

上一节的流程在本地实现了两个操作

  • git init
  • git remote add origin ‘git@github.com:${login}/${name}.git’

紧接着这一节按照本地的操作,我们应该实现 git add. / git commit -m’的操作。 本节实现initCommit()方法:

  • 首先检查是否有代码冲突
  • 然后检查代码是否有未提交
  • 然后判断远程分支是否已存在
    • 不存在的话直接push代码
    • 存在的话就需要使用git pull去拉取代码,且使用 ‘—allow-unrelated-histories:all’:null 参数。
  1. async initCommit(){
  2. await this.checkConflicted(); //检查代码冲突
  3. await this.checkNotCommitted();//检查代码未提交
  4. if(await this.checkRemoteMaster()){ //判断远程仓库master分支是否已存在
  5. await this.pullRemoteRepo('master',{
  6. '--allow-unrelated-histories':null
  7. })
  8. } else {
  9. await this.pushRemoteRepo('master') //如果不存在直接push代码
  10. }
  11. }
  12. async checkConflicted(){
  13. log.info('代码冲突检查')
  14. const status = await this.git.status()
  15. if(status.conflicted.length > 0 ){
  16. throw new Error('当然代码存在冲突,请手动处理合并后再试')
  17. }
  18. log.success('代码冲突检查通过')
  19. }
  20. async checkNotCommitted(){
  21. const status = await this.git.status()
  22. if(status.not_added.length >0 ||
  23. status.created.length >0 ||
  24. status.deleted.length>0 ||
  25. status.modified.length>0 ||
  26. status.renamed.length>0
  27. ){
  28. log.verbose('status',status)
  29. await this.git.add(status.not_added)
  30. await this.git.add(status.created)
  31. await this.git.add(status.deleted)
  32. await this.git.add(status.modified)
  33. await this.git.add(status.renamed)
  34. let message;
  35. while (!message) {
  36. message = (await inquirer.prompt({
  37. type:'text',
  38. name:'message',
  39. message:'请输入commit信息'
  40. })).message
  41. }
  42. await this.git.commit(message)
  43. log.success('本次commit提交成功!')
  44. }
  45. }
  46. async checkRemoteMaster(){
  47. // git ls-remote
  48. return (await this.git.listRemote(['--refs'])).indexOf('refs/heads/master') >=0
  49. }
  50. async pushRemoteRepo(branchName){
  51. log.info(`推送代码至${branchName} 分支`)
  52. await this.git.push('origin',branchName)
  53. log.success('推送代码成功!')
  54. }
  55. async pullRemoteRepo(branchName,options){
  56. log.info(`同步远程${branchName}分支代码`)
  57. await this.git.pull('origin',branchName,options)
  58. .catch(err=>{
  59. log.error(err.message)
  60. })
  61. }

第五章 GitFlow本地仓库代码自动提交


5-1 自动生成开发分支原理讲解1

第一遍:这节课听的有点懵逼。

点击查看【processon】

5-2 自动生成开发分支功能开发

本节主要实现为 获取远程发布分支列表(git ls-remote —refs)和获取远程最新发布分支号(通过正则匹配release分支,并排序获取最新分支),详细代码如下:

  1. const semver = require('semver')
  2. const VERSION_RELEASE = 'release'
  3. const VERSION_DEVELOP = 'dev'
  4. async commit(){
  5. // 1.生成开发分支
  6. await this.getCorrectVersion()
  7. // 2.在开发分支上提交代码
  8. // 3.合并远程开发分支
  9. //4.推送开发分支
  10. }
  11. async getCorrectVersion(type){
  12. // 1.获取远程发布分支
  13. // 规范:release/x.y.z ,dev/x.y.z
  14. // 版本号递增规范:major/minor/patch
  15. log.info('获取远程仓库代码分支')
  16. const remoteBranchList = await this.getRemoteBranchList(VERSION_RELEASE)
  17. let releaseVersion = null;
  18. if(remoteBranchList && remoteBranchList.length>0){
  19. releaseVersion = remoteBranchList[0]
  20. }
  21. log.verbose('releaseVersion',releaseVersion)
  22. }
  23. async getRemoteBranchList(type){
  24. const remoteList = await this.git.listRemote(['--refs'])
  25. let reg;
  26. if(type === VERSION_RELEASE ){
  27. reg = /.+?refs\/tags\/release\/(\d+\.\d+\.\d+)/g
  28. }else{
  29. }
  30. return remoteList.split('\n').map(remote =>{
  31. const match = reg.exec(remote)
  32. reg.lastIndex = 0
  33. if(match &&semver.valid(match[1]) ){
  34. return match[1]
  35. }
  36. }).filter(_ => _ ).sort((a,b) => {
  37. if(semver.lte(b,a)){
  38. if(a===b) return 0;
  39. return -1
  40. }
  41. return 1
  42. })
  43. }

5-3 高端操作:自动升级版本号功能开发

根据5-1图示,上两节我们完成的部分为:获取远程发布分支号列表、获取远程最新发布分支号,并在上节代码中经过处理,拿到了最新的远程发布的版本号,接下来我们实现

  • 判断最新发布版本号是否存在
    • 不存在:生成本地开发分支
    • 存在:与本地开发分支版本号通过semver对比
      • 本地分支小于远程最新发布分支版本号
        • 通过inquirer询问选择本地版本的升级方式
        • 获取选择升级的版本号
        • 重新写入到本地package.json中的version中去
      • 本地分支大于远程最新发布分支版本号
  1. this.branch = null //本地开发分支
  2. //接着上一节的代码,在getCorrectVersion方法中继续:
  3. //2.生成本地开发分支
  4. const devVersion = this.version
  5. if(!releaseVersion){ // 不存在远程发布分支
  6. this.branch = `${VERSION_DEVELOP}/${devVersion}`
  7. }else if(semver.gt(this.version,releaseVersion)){ //本地分支大于远程发布分支
  8. log.info('当前版本大于线上最新版本',`${devVersion} >= ${releaseVersion}`)
  9. this.branch = `${VERSION_DEVELOP}/${devVersion}`
  10. } else {
  11. log.info('当前线上版本大于本地版本',`${releaseVersion} > ${devVersion}`)
  12. const incType = (await inquirer.prompt({
  13. type:'list',
  14. name:'incType',
  15. message:'自动升级版本,请选择升级版本',
  16. default:'patch',
  17. choices:[{
  18. name:`小版本(${releaseVersion} -> ${semver.inc(releaseVersion,'patch')})`,
  19. value:'patch'
  20. },{
  21. name:`中版本(${releaseVersion} -> ${semver.inc(releaseVersion,'minor')})`,
  22. value:'minor'
  23. },{
  24. name:`大版本(${releaseVersion} -> ${semver.inc(releaseVersion,'major')})`,
  25. value:'major'
  26. }]
  27. })).incType
  28. const incVersion = semver.inc(releaseVersion,incType)
  29. this.branch = `${VERSION_DEVELOP}/${incVersion}`
  30. this.version = incVersion
  31. }
  32. log.verbose('本地开发分支',this.branch)
  33. //3.将version同步到package.json
  34. this.syncVersionToPackageJson()
  35. syncVersionToPackageJson(){
  36. const pkg = fse.readJsonSync(`${this.dir}/package.json`)
  37. if(pkg && pkg.version!== this.version){
  38. pkg.version = this.version
  39. fse.writeJsonSync(`${this.dir}/package.json`,pkg,{spaces:2})
  40. }
  41. }


5-4 GitFlow代码自动提交流程梳理+stash区检查功能开发

点击查看【processon】

本地执行git status 有未提交的代码时,执行 git stash将未提交的代码缓存在stash区当中。 然后通过git status命令发现,没有代码可提交 这里温习了git stash的个命令:git stash / git stash list / git stash pop

本节代码实现

  1. async checkStash(){
  2. //1. 检查stash list
  3. const stashList = await this.git.stashList()
  4. if(stashList.all.length >0){
  5. await this.git.stash['pop']
  6. log.success('stash pop成功')
  7. }
  8. }

5-5 代码冲突处理+Git代码删除后还原方法讲解

本节以及上一节听的有些懵逼,需要第二遍重新学习

5-6 自动切换开发分支+合并远程分支代码+推送代码功能开发

先暂时略过笔记。

第六章 本周加餐:Node编码最佳实践


6-1 Node最佳实践学习说明

6-2 Node项目架构最佳实践

6-3 Node异常处理最佳实践

代码示例: 捕获 unresolved 和 rejected 的 promise

  1. process.on('unhandledRejection', (reason, p) => {
  2. //我刚刚捕获了一个未处理的promise rejection, 因为我们已经有了对于未处理错误的后备的处理机制(见下面), 直接抛出,让它来处理
  3. throw reason;
  4. });
  5. process.on('uncaughtException', (error) => {
  6. //我刚收到一个从未被处理的错误,现在处理它,并决定是否需要重启应用
  7. errorManagement.handler.handleError(error);
  8. if (!errorManagement.handler.isTrustedError(error))
  9. process.exit(1);
  10. });

6-4 Node编码规范最佳实践

6-5 Node测试+安全最佳实践