@@ -2,11 +2,19 @@ import { mkdir, rm, writeFile } from 'node:fs/promises';
2
2
import { join } from 'node:path' ;
3
3
import { type SimpleGit , simpleGit } from 'simple-git' ;
4
4
import { expect } from 'vitest' ;
5
- import { getGitRoot , getLatestCommit , toGitPath } from './git' ;
5
+ import {
6
+ getCurrentBranchOrTag ,
7
+ getGitRoot ,
8
+ getLatestCommit ,
9
+ guardAgainstLocalChanges ,
10
+ safeCheckout ,
11
+ toGitPath ,
12
+ } from './git' ;
6
13
import { toUnixPath } from './transform' ;
7
14
8
- describe ( 'git utils' , ( ) => {
15
+ describe ( 'git utils in a git repo with a branch and commits ' , ( ) => {
9
16
const baseDir = join ( process . cwd ( ) , 'tmp' , 'testing-git-repo' ) ;
17
+ const changesDir = join ( baseDir , 'changes-dir' ) ;
10
18
let git : SimpleGit ;
11
19
12
20
beforeAll ( async ( ) => {
@@ -21,12 +29,26 @@ describe('git utils', () => {
21
29
22
30
await git . add ( 'README.md' ) ;
23
31
await git . commit ( 'Create README' ) ;
32
+
33
+ await git . checkout ( [ 'master' ] ) ;
24
34
} ) ;
25
35
26
36
afterAll ( async ( ) => {
27
37
await rm ( baseDir , { recursive : true , force : true } ) ;
28
38
} ) ;
29
39
40
+ beforeEach ( async ( ) => {
41
+ await git . checkout ( [ '-b' , 'feature-branch' ] ) ;
42
+ await git . checkout ( [ 'master' ] ) ;
43
+ } ) ;
44
+
45
+ afterEach ( async ( ) => {
46
+ // @TODO try why restore/stash/clean/reset hard etc does not work
47
+ await rm ( changesDir , { recursive : true , force : true } ) ;
48
+ await git . checkout ( [ 'master' ] ) ;
49
+ await git . deleteLocalBranch ( 'feature-branch' ) ;
50
+ } ) ;
51
+
30
52
it ( 'should log latest commit' , async ( ) => {
31
53
const gitCommitDateRegex =
32
54
/ ^ ( M o n | T u e | W e d | T h u | F r i | S a t | S u n ) ( J a n | F e b | M a r | A p r | M a y | J u n | J u l | A u g | S e p | O c t | N o v | D e c ) \d { 1 , 2 } \d { 2 } : \d { 2 } : \d { 2 } \d { 4 } [ + | - ] \d { 4 } $ / ;
@@ -60,4 +82,79 @@ describe('git utils', () => {
60
82
'Backend/API/Startup.cs' ,
61
83
) ;
62
84
} ) ;
85
+
86
+ it ( 'guardAgainstLocalChanges should throw if history is dirty' , async ( ) => {
87
+ await mkdir ( changesDir , { recursive : true } ) ;
88
+ await writeFile ( join ( changesDir , 'change.md' ) , '# hello-change\n' ) ;
89
+ await expect ( guardAgainstLocalChanges ( git ) ) . rejects . toThrow (
90
+ 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.' ,
91
+ ) ;
92
+ } ) ;
93
+
94
+ it ( 'guardAgainstLocalChanges should not throw if history is clean' , async ( ) => {
95
+ await expect ( guardAgainstLocalChanges ( git ) ) . resolves . toBeUndefined ( ) ;
96
+ } ) ;
97
+
98
+ it ( 'safeCheckout should checkout target branch in clean state' , async ( ) => {
99
+ await expect ( git . branch ( ) ) . resolves . toEqual (
100
+ expect . objectContaining ( { current : 'master' } ) ,
101
+ ) ;
102
+ await expect (
103
+ safeCheckout ( 'feature-branch' , { } , git ) ,
104
+ ) . resolves . toBeUndefined ( ) ;
105
+ await expect ( git . branch ( ) ) . resolves . toEqual (
106
+ expect . objectContaining ( { current : 'feature-branch' } ) ,
107
+ ) ;
108
+ } ) ;
109
+
110
+ it ( 'safeCheckout should throw if history is dirty' , async ( ) => {
111
+ await mkdir ( changesDir , { recursive : true } ) ;
112
+ await writeFile ( join ( changesDir , 'change.md' ) , '# hello-change\n' ) ;
113
+ await expect ( safeCheckout ( 'master' , { } , git ) ) . rejects . toThrow (
114
+ 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.' ,
115
+ ) ;
116
+ } ) ;
117
+
118
+ it ( 'safeCheckout should clean local changes and check out to feature-branch' , async ( ) => {
119
+ // needs to get reset to be clean
120
+ await mkdir ( changesDir , { recursive : true } ) ;
121
+ await writeFile ( join ( changesDir , 'change.md' ) , '# hello-change\n' ) ;
122
+ // needs to get cleaned to be clean
123
+ await writeFile ( join ( baseDir , 'README.md' ) , '# hello-world-2\n' ) ;
124
+
125
+ await expect (
126
+ safeCheckout ( 'feature-branch' , { forceCleanStatus : true } , git ) ,
127
+ ) . resolves . toBeUndefined ( ) ;
128
+ await expect ( git . branch ( ) ) . resolves . toEqual (
129
+ expect . objectContaining ( { current : 'feature-branch' } ) ,
130
+ ) ;
131
+ await expect ( git . status ( ) ) . resolves . toEqual (
132
+ expect . objectContaining ( { files : [ ] } ) ,
133
+ ) ;
134
+ } ) ;
135
+
136
+ it ( 'getCurrentBranchOrTag should log current branch' , async ( ) => {
137
+ await expect ( getCurrentBranchOrTag ( git ) ) . resolves . toBe ( 'master' ) ;
138
+ } ) ;
139
+ } ) ;
140
+
141
+ describe ( 'git utils in a git repo without a branch and commits' , ( ) => {
142
+ const baseDir = join ( process . cwd ( ) , 'tmp' , 'testing-git-repo' ) ;
143
+ let git : SimpleGit ;
144
+
145
+ beforeAll ( async ( ) => {
146
+ await mkdir ( baseDir , { recursive : true } ) ;
147
+ git = simpleGit ( baseDir ) ;
148
+ await git . init ( ) ;
149
+ } ) ;
150
+
151
+ afterAll ( async ( ) => {
152
+ await rm ( baseDir , { recursive : true , force : true } ) ;
153
+ } ) ;
154
+
155
+ it ( 'getCurrentBranchOrTag should throw if no branch is given' , async ( ) => {
156
+ await expect ( getCurrentBranchOrTag ( git ) ) . rejects . toThrow (
157
+ 'Could not get current tag or branch.' ,
158
+ ) ;
159
+ } ) ;
63
160
} ) ;
0 commit comments