【问题标题】:How to include git revision into angular-cli application?如何将 git 修订版包含到 angular-cli 应用程序中?
【发布时间】:2017-06-28 13:11:34
【问题描述】:

我需要在我的 angular2 应用程序的 about 页面上显示 git 修订版。该项目基于angular-cli。

如何扩展构建以便将 git 修订版放入例如environment.ts 或应用程序可访问的其他位置?

【问题讨论】:

  • 我猜 Angular-cli 缺少所需的预构建脚本功能。但我猜你可能会使用普通的 NPM 脚本

标签: angular angular-cli


【解决方案1】:

正如@Yuri 所建议的,我能够通过使用npm 脚本来解决这个问题。

  1. 在 angular-cli 项目的根目录中定义 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'}
        );
    });

  1. 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",
    ...
}
  1. 在应用程序中使用生成的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
  • 如何生成src/environments/versions.ts文件?我调用了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 语句。
【解决方案2】:

其他答案很有帮助,但我更喜欢更简单、更直接的方法。这是我的。

运行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 或您想使用的任何其他地方。

【讨论】:

  • npm 错误! notsup inotify@1.4.2 不支持的平台:想要 {"os":"linux","arch":"any"}(当前:{"os":"win32","arch":"x64"})
  • 奇怪。我在我的 Windows 10 x64 机器上运行它没有问题,它在 AppVeyor 的 VS2017 图像上也运行良好。
  • @wildloop 安装git-describe的npm语法应该是npm install git-describe --save-dev
【解决方案3】:
  1. 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

  1. 在构建之前或之后运行此代码。将新脚本添加到 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"
  }
  1. 运行:- npm run build.prod

欢迎提出代码改进建议 :)

【讨论】:

  • 这很好,我唯一的批评是你拼错了变量chidProcess
  • 感谢您告诉我。已解决该问题
  • 不错的一个!您可以在生成的json文件中添加version: process.env.npm_package_version,添加版本。
【解决方案4】:

我喜欢保持简单。可以添加到你的 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}”在本地运行,因为它只是在构建后被替换。 如果您在构建之前替换它,显然无法在未来的本地构建中替换它,并且肯定会不小心签入。

---- 更新----

最终创建了一个库来提取各种信息。最终只使用了版本、构建时间和提交时间。

https://www.npmjs.com/package/@rippell/ngx-build-info

【讨论】:

  • 这可能仅适用于具有sed 命令的系统(linux:是,windows:否)
  • 绝对正确,部分原因是我最终创建了 npm 库
【解决方案5】:

显示分支名称和提交哈希

我有一点不同的方法,灵感来自主项目目录中的答案 repo Seba ArceJeroen

  • 执行: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.jsonscripts 添加"build": "node git-version-gen.js &amp;&amp; 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 不授予对分支名称的访问权限)

  • 1234563 ... - 但是选择取决于您。
  • 跨平台 - 在 Azure(windows)、MacO(~linux-like)上测试

【讨论】:

    【解决方案6】:

    我已经通过生成在安装后运行的预构建脚本并在任何与角度相关的脚本之前运行来完成它

    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

    【讨论】:

    • 什么是 require('fs')、require('git-rev-sync') 和 require('mkdirp') 我需要安装它们吗
    【解决方案7】:

    对于角度 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 编译器能够识别它。

    1. 在您的 /src 下创建 typings.d.ts 文件(在此处阅读有关 typings.d.ts 的更多信息:https://angular.io/guide/typescript-configuration#typescript-typings

    /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
    

    【讨论】:

      【解决方案8】:

      我选择了 Vilmantas Baranauskas 的修改版

      我将 src/index.html 移动到 src/index.base.html 并在 HEAD 中添加了一个空的 &lt;meta name="revision" content=""&gt;

      例子:

      <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 部分中

      【讨论】:

        【解决方案9】:

        使用 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-10-20
          • 2012-10-24
          • 2010-10-27
          • 1970-01-01
          • 2018-10-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多