Reputation: 6726
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 example into environment.ts
or other place accessible to application?
Upvotes: 47
Views: 31930
Reputation: 802
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 :)
Upvotes: 18
Reputation: 6726
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",
...
}
Upvotes: 58
Reputation: 1139
I like to keep things simple. Can add to your index.html:
<script>window.version = '{git-hash}';</script>
Then add a postbuild
script to your package.json
:
"postbuild": "sed -i '' \"s/{git\\-hash}/$(git rev-parse --short HEAD)/g\" dist/*/index.html"
Not elegant by any means. Personally I create an object on window
with various information about the build (time, version, and a release summary link).
To stay more 'pure', stick the {git-hash}
string in environment.prod.ts
and run the sed
against all main-*.js
files produced.
"postbuild": "sed -i '' \"s/{git\\-hash}/$(git rev-parse --short HEAD)/g\" dist/*/main-*.js"
Note you'll always see '{git-hash}' running locally as it's only replaced post-build. If you replace it before the build, obviously can't replace it on future builds locally and would most definitely accidentally check that in.
---- UPDATE ----
Ended up creating a library to pull various information. Only ended up using version, build time, and commitTime personally.
https://www.npmjs.com/package/@rippell/ngx-build-info
Upvotes: 10
Reputation: 760
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
Upvotes: 2
Reputation: 2590
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
Upvotes: 2
Reputation: 92567
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)
Upvotes: 8
Reputation: 63790
The other answers were helpful, but I preferred a more simple, direct approach. Here's mine.
Run npm install git-describe --save-dev
. Then add git-version.js
to the root:
// 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);
Optionally you can add /git-version.json
to your .gitignore
file.
Update your package.json
to do something like this:
"scripts": {
"build": "node git-version.js && ng build"
}
Then add version-info.ts
to the root of your project:
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' };
}
})();
And import
the versionInfo
in your app.component.ts
or anywhere else you'd want to use it.
Upvotes: 26
Reputation: 41
For angular 6
1 Install git-describe as a dev dependency
npm i git-describe -s
2 On your root project create a 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);
The output of the grab-git-info.js script will be the ‘git-version.json’ file under /src/ which will contain all the git info needed by our app.
In order to be able to import the json file (or any other json file) we need to add a definition file declaring of the added module so that the Typescript compiler will recognize it.
/src/typings.d.ts:
declare module '*.json' {
const value: any;
export default value;
}
From this point on you can import any json file located under /src as a module!
In your component you can import this json
import * as data from '../../../git-version.json';
...
public git = data;
In the html
Rev: {{git.hash}}
Finally Add and most important, run the script before build
In package.json add:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "node grab-git-info && ng build",
And run the app with
npm run build
Upvotes: 2
Reputation: 10633
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
Upvotes: 0