1- import { spawnSync } from 'child_process' ;
1+ import { spawnSync , SpawnSyncReturns } from 'child_process' ;
22
33/**
44 * Class that can be used to execute Git commands within a given project directory.
@@ -10,65 +10,89 @@ export class GitClient {
1010
1111 constructor ( public projectDir : string , public remoteGitUrl : string ) { }
1212
13+ /**
14+ * Spawns a child process running Git. The "stderr" output is inherited and will be printed
15+ * in case of errors. This makes it easier to debug failed commands.
16+ */
17+ private _spawnGitProcess ( args : string [ ] ) : SpawnSyncReturns < string > {
18+ return spawnSync ( 'git' , args , {
19+ cwd : this . projectDir ,
20+ stdio : [ 'pipe' , 'pipe' , 'inherit' ] ,
21+ encoding : 'utf8' ,
22+ } ) ;
23+ }
24+
1325 /** Gets the currently checked out branch for the project directory. */
1426 getCurrentBranch ( ) {
15- return spawnSync ( 'git' , [ 'symbolic-ref' , '--short' , 'HEAD' ] , { cwd : this . projectDir } )
16- . stdout . toString ( ) . trim ( ) ;
27+ return this . _spawnGitProcess ( [ 'symbolic-ref' , '--short' , 'HEAD' ] ) . stdout . trim ( ) ;
1728 }
1829
1930 /** Gets the commit SHA for the specified remote repository branch. */
2031 getRemoteCommitSha ( branchName : string ) : string {
21- return spawnSync ( 'git' , [ 'ls-remote' , this . remoteGitUrl , '-h' , `refs/heads/${ branchName } ` ] ,
22- { cwd : this . projectDir } ) . stdout . toString ( ) . split ( '\t' ) [ 0 ] . trim ( ) ;
32+ return this . _spawnGitProcess ( [ 'ls-remote' , this . remoteGitUrl , '-h' ,
33+ `refs/heads/${ branchName } ` ] )
34+ . stdout . split ( '\t' ) [ 0 ] . trim ( ) ;
2335 }
2436
2537 /** Gets the latest commit SHA for the specified git reference. */
2638 getLocalCommitSha ( refName : string ) {
27- return spawnSync ( 'git' , [ 'rev-parse' , refName ] , { cwd : this . projectDir } )
28- . stdout . toString ( ) . trim ( ) ;
39+ return this . _spawnGitProcess ( [ 'rev-parse' , refName ] ) . stdout . trim ( ) ;
2940 }
3041
3142 /** Gets whether the current Git repository has uncommitted changes. */
3243 hasUncommittedChanges ( ) : boolean {
33- return spawnSync ( 'git' , [ 'diff-index' , '--quiet' , 'HEAD' ] , { cwd : this . projectDir } ) . status !== 0 ;
44+ return this . _spawnGitProcess ( [ 'diff-index' , '--quiet' , 'HEAD' ] ) . status !== 0 ;
3445 }
3546
3647 /** Checks out an existing branch with the specified name. */
3748 checkoutBranch ( branchName : string ) : boolean {
38- return spawnSync ( 'git' , [ 'checkout' , branchName ] , { cwd : this . projectDir } ) . status === 0 ;
49+ return this . _spawnGitProcess ( [ 'checkout' , branchName ] ) . status === 0 ;
3950 }
4051
4152 /** Creates a new branch which is based on the previous active branch. */
4253 checkoutNewBranch ( branchName : string ) : boolean {
43- return spawnSync ( 'git' , [ 'checkout' , '-b' , branchName ] , { cwd : this . projectDir } ) . status === 0 ;
54+ return this . _spawnGitProcess ( [ 'checkout' , '-b' , branchName ] ) . status === 0 ;
4455 }
4556
4657 /** Stages all changes by running `git add -A`. */
4758 stageAllChanges ( ) : boolean {
48- return spawnSync ( 'git' , [ 'add' , '-A' ] , { cwd : this . projectDir } ) . status === 0 ;
59+ return this . _spawnGitProcess ( [ 'add' , '-A' ] ) . status === 0 ;
4960 }
5061
5162 /** Creates a new commit within the current branch with the given commit message. */
5263 createNewCommit ( message : string ) : boolean {
53- return spawnSync ( 'git' , [ 'commit' , '-m' , message ] , { cwd : this . projectDir } ) . status === 0 ;
64+ return this . _spawnGitProcess ( [ 'commit' , '-m' , message ] ) . status === 0 ;
5465 }
5566
5667 /** Gets the title of a specified commit reference. */
5768 getCommitTitle ( commitRef : string ) : string {
58- return spawnSync ( 'git' , [ 'log' , '-n1' , '--format' , '%s' , commitRef ] , { cwd : this . projectDir } )
59- . stdout . toString ( ) . trim ( ) ;
69+ return this . _spawnGitProcess ( [ 'log' , '-n1' , '--format="%s"' , commitRef ] ) . stdout . trim ( ) ;
6070 }
6171
6272 /** Creates a tag for the specified commit reference. */
6373 createTag ( commitRef : string , tagName : string , message : string ) : boolean {
64- return spawnSync ( 'git' , [ 'tag' , tagName , '-m' , message ] , { cwd : this . projectDir } ) . status === 0 ;
74+ return this . _spawnGitProcess ( [ 'tag' , tagName , '-m' , message ] ) . status === 0 ;
75+ }
76+
77+ /** Checks whether the specified tag exists locally. */
78+ hasLocalTag ( tagName : string ) {
79+ return this . _spawnGitProcess ( [ 'rev-parse' , `refs/tags/${ tagName } ` ] ) . status === 0 ;
80+ }
81+
82+ /** Gets the Git SHA of the specified local tag. */
83+ getShaOfLocalTag ( tagName : string ) {
84+ return this . _spawnGitProcess ( [ 'rev-parse' , `refs/tags/${ tagName } ` ] ) . stdout . trim ( ) ;
85+ }
86+
87+ /** Gets the Git SHA of the specified remote tag. */
88+ getShaOfRemoteTag ( tagName : string ) : string {
89+ return this . _spawnGitProcess ( [ 'ls-remote' , this . remoteGitUrl , '-t' , `refs/tags/${ tagName } ` ] )
90+ . stdout . split ( '\t' ) [ 0 ] . trim ( ) ;
6591 }
6692
6793 /** Pushes the specified tag to the remote git repository. */
6894 pushTagToRemote ( tagName : string ) : boolean {
69- return spawnSync ( 'git' , [ 'push' , this . remoteGitUrl , `refs/tags/${ tagName } ` ] , {
70- cwd : this . projectDir
71- } ) . status === 0 ;
95+ return this . _spawnGitProcess ( [ 'push' , this . remoteGitUrl , `refs/tags/${ tagName } ` ] ) . status === 0 ;
7296 }
7397}
7498
0 commit comments