Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 结合Git Commit 版本处理 #112

Open
reng99 opened this issue Mar 26, 2022 · 0 comments
Open

Angular 结合Git Commit 版本处理 #112

reng99 opened this issue Mar 26, 2022 · 0 comments
Labels
blog a single blog

Comments

@reng99
Copy link
Owner

reng99 commented Mar 26, 2022

version.png
上图是页面上展示的测试环境/开发环境版本信息。

后面有介绍

version-txt.png
上图表示的是每次提交的Git Commit的信息,当然,这里我是每次提交都记录,你可以在每次构建的时候记录。

So,我们接下来用 Angular 实现下效果,ReactVue 同理。

搭建环境

因为这里的重点不是搭建环境,我们直接用 angular-cli 脚手架直接生成一个项目就可以了。

Step 1: 安装脚手架工具

npm install -g @angular/cli

Step 2: 创建一个项目

# ng new PROJECT_NAME
ng new ng-commit

Step 3: 运行项目

npm run start

项目运行起来,默认监听4200端口,直接在浏览器打开http://localhost:4200/就行了。

4200 端口没被占用的前提下

此时,ng-commit 项目重点文件夹 src 的组成如下:

src
├── app                                               // 应用主体
│   ├── app-routing.module.ts                         // 路由模块
│   .
│   └── app.module.ts                                 // 应用模块
├── assets                                            // 静态资源
├── main.ts                                           // 入口文件
.
└── style.less                                        // 全局样式

上面目录结构,我们后面会在 app 目录下增加 services 服务目录,和 assets 目录下的 version.json文件。

记录每次提交的信息

在根目录创建一个文件version.txt,用于存储提交的信息;在根目录创建一个文件commit.js,用于操作提交信息。

重点在commit.js,我们直接进入主题:

const execSync = require('child_process').execSync;
const fs = require('fs')
const versionPath = 'version.txt'
const buildPath = 'dist'
const autoPush = true;
const commit = execSync('git show -s --format=%H').toString().trim(); // 当前的版本号

let versionStr = ''; // 版本字符串

if(fs.existsSync(versionPath)) {
  versionStr = fs.readFileSync(versionPath).toString() + '\n';
}

if(versionStr.indexOf(commit) != -1) {
  console.warn('\x1B[33m%s\x1b[0m', 'warming: 当前的git版本数据已经存在了!\n')
} else {
  let name = execSync('git show -s --format=%cn').toString().trim(); // 姓名
  let email = execSync('git show -s --format=%ce').toString().trim(); // 邮箱
  let date = new Date(execSync('git show -s --format=%cd').toString()); // 日期
  let message = execSync('git show -s --format=%s').toString().trim(); // 说明
  versionStr = `git:${commit}\n作者:${name}<${email}>\n日期:${date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+' '+date.getHours()+':'+date.getMinutes()}\n说明:${message}\n${new Array(80).join('*')}\n${versionStr}`;
  fs.writeFileSync(versionPath, versionStr);
  // 写入版本信息之后,自动将版本信息提交到当前分支的git上
  if(autoPush) { // 这一步可以按照实际的需求来编写
    execSync(`git add ${ versionPath }`);
    execSync(`git commit ${ versionPath } -m 自动提交版本信息`);
    execSync(`git push origin ${ execSync('git rev-parse --abbrev-ref HEAD').toString().trim() }`)
  }
}

if(fs.existsSync(buildPath)) {
  fs.writeFileSync(`${ buildPath }/${ versionPath }`, fs.readFileSync(versionPath))
}

上面的文件可以直接通过 node commit.js 进行。为了方便管理,我们在 package.json 上加上命令行:

"scripts": {
  "commit": "node commit.js"
}

那样,使用 npm run commit 同等 node commit.js 的效果。

生成版本信息

有了上面的铺垫,我们可以通过 commit 的信息,生成指定格式的版本信息version.json了。

在根目录中新建文件version.js用来生成版本的数据。

const execSync = require('child_process').execSync;
const fs = require('fs')
const targetFile = 'src/assets/version.json'; // 存储到的目标文件

const commit = execSync('git show -s --format=%h').toString().trim(); //当前提交的版本号,hash 值的前7位
let date = new Date(execSync('git show -s --format=%cd').toString()); // 日期
let message = execSync('git show -s --format=%s').toString().trim(); // 说明

let versionObj = {
  "commit": commit,
  "date": date,
  "message": message
};

const data = JSON.stringify(versionObj);

fs.writeFile(targetFile, data, (err) => {
  if(err) {
    throw err
  }
  console.log('Stringify Json data is saved.')
})

我们在 package.json 上加上命令行方便管理:

"scripts": {
  "version": "node version.js"
}

根据环境生成版本信息

针对不同的环境生成不同的版本信息,假设我们这里有开发环境 development,生产环境 production 和车测试环境 test

  • 生产环境版本信息是 major.minor.patch,如:1.1.0
  • 开发环境版本信息是 major.minor.patch:beta,如:1.1.0:beta
  • 测试环境版本信息是 major.minor.path-data:hash,如:1.1.0-2022.01.01:4rtr5rg

方便管理不同环境,我们在项目的根目录中新建文件如下:

config
├── default.json          // 项目调用的配置文件
├── development.json      // 开发环境配置文件
├── production.json       // 生产环境配置文件
└── test.json             // 测试环境配置文件

相关的文件内容如下:

// development.json
{
  "env": "development",
  "version": "1.3.0"
}
// production.json
{
  "env": "production",
  "version": "1.3.0"
}
// test.json
{
  "env": "test",
  "version": "1.3.0"
}

default.json 根据命令行拷贝不同环境的配置信息,在 package.json 中配置下:

"scripts": {
  "copyConfigProduction": "cp ./config/production.json ./config/default.json",
  "copyConfigDevelopment": "cp ./config/development.json ./config/default.json",
  "copyConfigTest": "cp ./config/test.json ./config/default.json",
}

Is easy Bro, right?

整合生成版本信息的内容,得到根据不同环境生成不同的版本信息,具体代码如下:

const execSync = require('child_process').execSync;
const fs = require('fs')
const targetFile = 'src/assets/version.json'; // 存储到的目标文件
const config = require('./config/default.json');

const commit = execSync('git show -s --format=%h').toString().trim(); //当前提交的版本号
let date = new Date(execSync('git show -s --format=%cd').toString()); // 日期
let message = execSync('git show -s --format=%s').toString().trim(); // 说明

let versionObj = {
  "env": config.env,
  "version": "",
  "commit": commit,
  "date": date,
  "message": message
};

// 格式化日期
const formatDay = (date) => {
  let formatted_date = date.getFullYear() + "." + (date.getMonth()+1) + "." +date.getDate()
    return formatted_date;
}

if(config.env === 'production') {
  versionObj.version = config.version
}

if(config.env === 'development') {
  versionObj.version = `${ config.version }:beta`
}

if(config.env === 'test') {
  versionObj.version = `${ config.version }-${ formatDay(date) }:${ commit }`
}

const data = JSON.stringify(versionObj);

fs.writeFile(targetFile, data, (err) => {
  if(err) {
    throw err
  }
  console.log('Stringify Json data is saved.')
})

package.json 中添加不同环境的命令行:

"scripts": {
  "build:production": "npm run copyConfigProduction && npm run version",
  "build:development": "npm run copyConfigDevelopment && npm run version",
  "build:test": "npm run copyConfigTest && npm run version",
}

生成的版本信息会直接存放在 assets 中,具体路径为 src/assets/version.json

结合 Angular 在页面中展示版本信息

最后一步,在页面中展示版本信息,这里是跟 angular 结合。

使用 ng generate service versionapp/services 目录中生成 version 服务。在生成的 version.service.ts 文件中添加请求信息,如下:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class VersionService {

  constructor(
    private http: HttpClient
  ) { }

  public getVersion():Observable<any> {
    return this.http.get('assets/version.json')
  }
}

要使用请求之前,要在 app.module.ts 文件挂载 HttpClientModule 模块:

import { HttpClientModule } from '@angular/common/http';

// ...

imports: [
  HttpClientModule
],

之后在组件中调用即可,这里是 app.component.ts 文件:

import { Component } from '@angular/core';
import { VersionService } from './services/version.service'; // 引入版本服务

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.less']
})
export class AppComponent {

  public version: string = '1.0.0'

  constructor(
    private readonly versionService: VersionService
  ) {}

  ngOnInit() {
    this.versionService.getVersion().subscribe({
      next: (data: any) => {
        this.version = data.version // 更改版本信息
      },
      error: (error: any) => {
        console.error(error)
      }
    })
  }
}

至此,我们完成了版本信息。我们最后来调整下 package.json 的命令:

"scripts": {
  "start": "ng serve",
  "version": "node version.js",
  "commit": "node commit.js",
  "build": "ng build",
  "build:production": "npm run copyConfigProduction && npm run version && npm run build",
  "build:development": "npm run copyConfigDevelopment && npm run version && npm run build",
  "build:test": "npm run copyConfigTest && npm run version && npm run build",
  "copyConfigProduction": "cp ./config/production.json ./config/default.json",
  "copyConfigDevelopment": "cp ./config/development.json ./config/default.json",
  "copyConfigTest": "cp ./config/test.json ./config/default.json"
}

使用 scripts 一是为了方便管理,而是方便 jenkins 构建方便调用。对于 jenkins 部分,感兴趣者可以自行尝试。

参考于后话

@reng99 reng99 added the blog a single blog label Mar 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blog a single blog
Projects
None yet
Development

No branches or pull requests

1 participant