I need to display git revision on my angular2 application\'s about page. The project is based on angular-cli.
How can build be extended so git revision is put for exampl
git-version.js
to the root.This code will execute git commands and write the output to the git-version.json
file.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);
This code will generate the git-version.json
file :-
{
"shortSHA": "0e786d4",
"SHA": "0e786d4ad3778463f6f30c28f254cc85c24eb4b3",
"branch": "master",
"lastCommitAuthor": "'saurabh'",
"lastCommitTime": "'Thu Apr 9 12:59:16 2020 +0530'",
"lastCommitMessage": "Commit message",
"lastCommitNumber": "200"
}
Modify above code as per your requirements.
Run: node git-version.js
This will generate the git-version.json
into src
directory.
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
suggestions for code improvement are welcome :)
Use gulp task using gulp-replace and git-rev-sync to add the hash and branch on build :
1) Create the gulp task
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) Add the following code to index.html :
{{git-branch}}@{{git-hash}}
3) Run
gulp build
I went with a modified version of Vilmantas Baranauskas
I moved src/index.html
to src/index.base.html
and added an empty <meta name="revision" content="">
inside the HEAD
Example:
<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">
Then modified git.version.ts
like this:
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' }
);
});
In this example I only put revision, but you can be more thorough and put branch and version inside your html HEAD section
I have a little different approach, inspired by answers repo Seba Arce and Jeroen , in main project directory:
npm install git-rev-sync --save
(this lib give acces to hash and branch name)git-version-gen.js
with following bodyconst 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
in scripts
add "build": "node git-version-gen.js && ng build ..."
app.component.ts
use it as followsimport { gitVersion } from '../../../environments/git-version';
// ...
constructor() {
console.log(`GIT branch:`,gitVersion.branch);
console.log(`GIT commit:`,gitVersion.commit);
}
What are advantages of use this?
we create here src/environments/git-version.ts
file so this is TypeScript, not .json - similar like you environments files - this will turn on support from your code editor (e.g VSCode)
you have acces to commit hash nad branch name (lib git-describe
not gives acces to branch name)
if you commit generated git-version.ts
file instead put it to .gitignore
then project will run without build (e.g. by ng serve ...
) and fresh developers will not be confused that there is missing some 'mystic' file... - however choice is up to you.
cross platform - tested on Azure (windows), MacOs (~linux-like)
I've done it by generating prebuild script run on postinstall and run before any angular related script
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' });
});
which generated git-tag.ts file:
export const gitTag = 'xxxxxxx';
and now u just use in component
import { gitTag } from '[pathToRoot]/generated/git-tag';
also add .gitignore
generated
As suggested by @Yuri, I was able to solve this by using npm
scripting.
git.version.ts
in the root of the angular-cli project: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",
...
}
Use the generated src/environments/versions.ts
in the application.
UPDATE 10/2018: Here is the more-readable version of the script, 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');
Note, when using angular-cli v7.0.6, I also had to change script invocation in the package.json
:
"scripts": {
...
"prebuild.prod": "ts-node -O '{\"module\": \"commonjs\"}' git.version.ts",
...
}