【发布时间】:2017-06-28 13:11:34
【问题描述】:
我需要在我的 angular2 应用程序的 about 页面上显示 git 修订版。该项目基于angular-cli。
如何扩展构建以便将 git 修订版放入例如environment.ts 或应用程序可访问的其他位置?
【问题讨论】:
-
我猜 Angular-cli 缺少所需的预构建脚本功能。但我猜你可能会使用普通的 NPM 脚本。
标签: angular angular-cli
我需要在我的 angular2 应用程序的 about 页面上显示 git 修订版。该项目基于angular-cli。
如何扩展构建以便将 git 修订版放入例如environment.ts 或应用程序可访问的其他位置?
【问题讨论】:
标签: angular angular-cli
正如@Yuri 所建议的,我能够通过使用npm 脚本来解决这个问题。
git.version.ts:import { Observable, combineLatest } from 'rxjs'
declare var require: any;
declare var process: any;
const fs = require('fs');
const exec = require('child_process').exec;
const revision = new Observable<string>(s => {
exec('git rev-parse --short HEAD',
(error: Error, stdout, stderr) => {
if (error !== null) {
console.log('git error: ' + error + stderr);
}
s.next(stdout.toString().trim());
s.complete();
});
});
const branch = new Observable<string>(s => {
exec('git rev-parse --abbrev-ref HEAD',
(error: Error, stdout, stderr) => {
if (error !== null) {
console.log('git error: ' + error + stderr);
}
s.next(stdout.toString().trim());
s.complete();
});
});
combineLatest(revision, branch)
.subscribe(([revision, branch]) => {
console.log(`version: '${process.env.npm_package_version}', revision: '${revision}', branch: '${branch}'`);
const content = '// this file is automatically generated by git.version.ts script\n' +
`export const versions = {version: '${process.env.npm_package_version}', revision: '${revision}', branch: '${branch}'};`;
fs.writeFileSync(
'src/environments/versions.ts',
content,
{encoding: 'utf8'}
);
});
package.json 中添加了预构建挂钩:"scripts": {
"ng": "ng",
...
"start": "ng serve --proxy proxy-config.json",
"prebuild.prod": "ts-node -O \"{\\\"module\\\":\\\"commonjs\\\"}\" git.version.ts",
"build.prod": "ng build -prod",
...
}
在应用程序中使用生成的src/environments/versions.ts。
UPDATE 10/2018:这是脚本的可读性更强的版本,rxjs-version-agnostic:
import { writeFileSync } from 'fs';
import { dedent } from 'tslint/lib/utils';
import { promisify } from 'util';
import * as child from 'child_process';
const exec = promisify(child.exec);
async function createVersionsFile(filename: string) {
const revision = (await exec('git rev-parse --short HEAD')).stdout.toString().trim();
const branch = (await exec('git rev-parse --abbrev-ref HEAD')).stdout.toString().trim();
console.log(`version: '${process.env.npm_package_version}', revision: '${revision}', branch: '${branch}'`);
const content = dedent`
// this file is automatically generated by git.version.ts script
export const versions = {
version: '${process.env.npm_package_version}',
revision: '${revision}',
branch: '${branch}'
};`;
writeFileSync(filename, content, {encoding: 'utf8'});
}
createVersionsFile('src/environments/versions.ts');
注意,在使用 angular-cli v7.0.6 时,我还必须更改 package.json 中的脚本调用:
"scripts": {
...
"prebuild.prod": "ts-node -O '{\"module\": \"commonjs\"}' git.version.ts",
...
}
【讨论】:
ts-node git.version.ts 命令不起作用,我不知道为什么会这样:Did you mean one of these? rebuild prefix profile
angular 6 / rxjs 6 的人:将导入更改为import { Observable, combineLatest } from 'rxjs';,然后将Observable.combineLatest 替换为combineLatest。
git describe --abbrev=0 --tags
ng prebuild.prod 命令,但没有任何反应。我等了几分钟,但没有输出。我的版本:bash Angular CLI: 6.0.8 Node: 8.11.1 OS: win32 x64 Angular: 5.2.10 Package Version ----------------------------------------------------------- @angular/cli 6.0.8 @angular/pwa 0.6.5 @angular/service-worker 5.2.11 @ngtools/webpack 6.0.5 rxjs 5.5.10
-O '{\"module\": \"commonjs\"}' in package.json 对我不起作用(win10)。我不得不删除它并将 git.version.ts 中的导入更改为 require 语句。
其他答案很有帮助,但我更喜欢更简单、更直接的方法。这是我的。
运行npm install git-describe --save-dev。然后在根目录下添加git-version.js:
// This script runs operations *synchronously* which is normally not the best
// approach, but it keeps things simple, readable, and for now is good enough.
const { gitDescribeSync } = require('git-describe');
const { writeFileSync } = require('fs');
const gitInfo = gitDescribeSync();
const versionInfoJson = JSON.stringify(gitInfo, null, 2);
writeFileSync('git-version.json', versionInfoJson);
您可以选择将/git-version.json 添加到您的.gitignore 文件中。
更新您的 package.json 以执行以下操作:
"scripts": {
"build": "node git-version.js && ng build"
}
然后将version-info.ts 添加到项目的根目录:
export const versionInfo = (() => {
try {
// tslint:disable-next-line:no-var-requires
return require('../../git-version.json');
} catch {
// In dev the file might not exist:
return { tag: 'v0.0.0', hash: 'dev' };
}
})();
还有import versionInfo 在您的app.component.ts 或您想使用的任何其他地方。
【讨论】:
git-describe的npm语法应该是npm install git-describe --save-dev
git-version.js 添加到根目录。此代码将执行git 命令并将输出写入git-version.json 文件。const childProcess = require('child_process');
const { writeFileSync } = require('fs');
const longSHA = childProcess.execSync("git rev-parse HEAD").toString().trim();
const shortSHA = childProcess.execSync("git rev-parse --short HEAD").toString().trim();
const branch = childProcess.execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
const authorName = childProcess.execSync("git log -1 --pretty=format:'%an'").toString().trim();
const commitTime = childProcess.execSync("git log -1 --pretty=format:'%cd'").toString().trim();
const commitMsg = childProcess.execSync("git log -1 --pretty=%B").toString().trim();
const totalCommitCount = childProcess.execSync("git rev-list --count HEAD").toString().trim();
const versionInfo = {
shortSHA: shortSHA,
SHA : longSHA,
branch: branch,
lastCommitAuthor: authorName,
lastCommitTime: commitTime,
lastCommitMessage: commitMsg,
lastCommitNumber: totalCommitCount
}
const versionInfoJson = JSON.stringify(versionInfo, null, 2);
writeFileSync('/src/git-version.json', versionInfoJson);
此代码将生成git-version.json 文件:-
{
"shortSHA": "0e786d4",
"SHA": "0e786d4ad3778463f6f30c28f254cc85c24eb4b3",
"branch": "master",
"lastCommitAuthor": "'saurabh'",
"lastCommitTime": "'Thu Apr 9 12:59:16 2020 +0530'",
"lastCommitMessage": "Commit message",
"lastCommitNumber": "200"
}
根据您的要求修改上述代码。
运行:node git-version.js 这将在src 目录中生成git-version.json。
package.json
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"build.prod": "node git-version.js && ng build --prod"
}
npm run build.prod
欢迎提出代码改进建议 :)
【讨论】:
chidProcess
version: process.env.npm_package_version,添加版本。
我喜欢保持简单。可以添加到你的 index.html 中:
<script>window.version = '{git-hash}';</script>
然后将postbuild 脚本添加到您的package.json:
"postbuild": "sed -i '' \"s/{git\\-hash}/$(git rev-parse --short HEAD)/g\" dist/*/index.html"
无论如何都不优雅。我个人在window 上创建了一个对象,其中包含有关构建的各种信息(时间、版本和发布摘要链接)。
要保持更“纯粹”,请将 {git-hash} 字符串粘贴到 environment.prod.ts 中,并对生成的所有 main-*.js 文件运行 sed。
"postbuild": "sed -i '' \"s/{git\\-hash}/$(git rev-parse --short HEAD)/g\" dist/*/main-*.js"
请注意,您总是会看到“{git-hash}”在本地运行,因为它只是在构建后被替换。 如果您在构建之前替换它,显然无法在未来的本地构建中替换它,并且肯定会不小心签入。
---- 更新----
最终创建了一个库来提取各种信息。最终只使用了版本、构建时间和提交时间。
【讨论】:
sed 命令的系统(linux:是,windows:否)
我有一点不同的方法,灵感来自主项目目录中的答案 repo Seba Arce 和 Jeroen :
npm install git-rev-sync --save(这个库可以访问哈希和分支名称)git-version-gen.js
const git = require('git-rev-sync');
const { writeFileSync } = require('fs');
const gitInfo = { commit: git.short(), commitLong: git.long(), branch: git.branch() };
const ts = 'export const gitVersion = ' + JSON.stringify(gitInfo, null, 2);
writeFileSync('src/environments/git-version.ts', ts);
package.json 在scripts 添加"build": "node git-version-gen.js && ng build ..."
app.component.ts如下使用import { gitVersion } from '../../../environments/git-version';
// ...
constructor() {
console.log(`GIT branch:`,gitVersion.branch);
console.log(`GIT commit:`,gitVersion.commit);
}
使用这个有什么好处?
我们在这里创建 src/environments/git-version.ts 文件,所以这是 TypeScript,而不是 .json - 类似于您的环境文件 - 这将打开您的代码编辑器(例如 VSCode)的支持
您有权提交哈希和分支名称(lib git-describe 不授予对分支名称的访问权限)
跨平台 - 在 Azure(windows)、MacO(~linux-like)上测试
【讨论】:
我已经通过生成在安装后运行的预构建脚本并在任何与角度相关的脚本之前运行来完成它
const fs = require('fs');
const git = require('git-rev-sync');
var mkdirp = require('mkdirp');
const releaseTag = git.tag();
const template = `export const gitTag = '${releaseTag}';\n`;
mkdirp('./generated', function(err) {
fs.writeFileSync('./generated/git-tag.ts', template, { encoding: 'UTF-8' });
});
其中生成了 git-tag.ts 文件:
export const gitTag = 'xxxxxxx';
现在你只是在组件中使用
import { gitTag } from '[pathToRoot]/generated/git-tag';
还添加 .gitignore
generated
【讨论】:
对于角度 6
1 安装 git-describe 作为开发依赖项
npm i git-describe -s
2 在你的根项目上创建一个 grab-git-info.js
const { gitDescribeSync } = require('git-describe');
const { writeFileSync } = require('fs');
const path = require('path');
const info = gitDescribeSync();
const infoJson = JSON.stringify(info, null, 2);
writeFileSync(path.join(__dirname, '/src/git-version.json'), infoJson);
grab-git-info.js 脚本的输出将是 /src/ 下的“git-version.json”文件,其中包含我们应用所需的所有 git 信息。
为了能够导入 json 文件(或任何其他 json 文件),我们需要添加一个定义文件来声明添加的模块,以便 Typescript 编译器能够识别它。
/src/typings.d.ts:
declare module '*.json' {
const value: any;
export default value;
}
从此时起,您可以将位于 /src 下的任何 json 文件作为模块导入!
在你的组件中你可以导入这个 json
import * as data from '../../../git-version.json';
...
public git = data;
在html中
Rev: {{git.hash}}
终于 添加最重要的是,在构建之前运行脚本
在 package.json 中添加:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "node grab-git-info && ng build",
然后运行应用程序
npm run build
【讨论】:
我选择了 Vilmantas Baranauskas 的修改版
我将 src/index.html 移动到 src/index.base.html 并在 HEAD 中添加了一个空的 <meta name="revision" content="">
例子:
<head>
<meta charset="utf-8">
<title>MySuperAwesome Angular</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="revision" content="">
<link rel="icon" type="image/x-icon" href="favicon.ico">
然后像这样修改git.version.ts:
import 'rxjs/add/observable/combineLatest';
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { Observable } from 'rxjs/Observable';
const indexBasePath = join(__dirname, 'src');
const exec = require('child_process').exec;
const revObs = new Observable<string>(s => {
exec('git rev-parse --short HEAD',
function (error: Error, stdout: Buffer, stderr: Buffer) {
if (error !== null) {
console.log('git error: ' + error + stderr);
}
s.next(stdout.toString().trim());
s.complete();
});
});
const branchObs = new Observable<string>(s => {
exec('git rev-parse --abbrev-ref HEAD',
function (error: Error, stdout: Buffer, stderr: Buffer) {
if (error !== null) {
console.log('git error: ' + error + stderr);
}
s.next(stdout.toString().trim());
s.complete();
});
});
Observable
.combineLatest(revObs, branchObs)
.subscribe(([revision, branch]) => {
console.log(`revision: '${revision}', branch: '${branch}'`);
const baseHTML = readFileSync(join(indexBasePath, 'index.base.html'), 'utf8');
const html = baseHTML
.replace('<meta name="revision" content="">', `<meta name="revision" content="${ revision }">`);
writeFileSync(
join(indexBasePath, 'index.html'),
html,
{ encoding: 'utf8' }
);
});
在这个例子中我只放了修订,但你可以更彻底地把分支和版本放在你的 html HEAD 部分中
【讨论】:
使用 gulp 任务使用 gulp-replace 和 git-rev-sync 在构建时添加哈希和分支:
1) 创建 gulp 任务
var gulp = require('gulp'),
replace = require('gulp-replace'),
git = require('git-rev-sync'),
gulp.task('git', function () {
gulp.src('src/index.html')
.pipe(replace('{{git-branch}}', git.branch()))
.pipe(replace('{{git-hash}}', git.short()))
.pipe(gulp.dest('src/'))
});
// Build Tasks
gulp.task('build', ['git']);
2) 在 index.html 中添加如下代码:
{{git-branch}}@{{git-hash}}
3) 运行
gulp build
【讨论】: