@@ -10,6 +10,7 @@ import * as path from 'path';
10
10
import * as os from 'os' ;
11
11
import { NamedPackageDir , Logger , fs } from '@salesforce/core' ;
12
12
import * as git from 'isomorphic-git' ;
13
+ import { pathIsInFolder } from './functions' ;
13
14
14
15
const gitIgnoreFileName = '.gitignore' ;
15
16
const stashedGitIgnoreFileName = '.BAK.gitignore' ;
@@ -43,6 +44,9 @@ interface CommitRequest {
43
44
message ?: string ;
44
45
}
45
46
47
+ // const gitIgnoreLocator = async (filepath: string) => {
48
+ // ( return filepath.endsWith(gitIgnoreFileName) ? filepath : null).filter(isString);
49
+ // }
46
50
export class ShadowRepo {
47
51
private static instance : ShadowRepo ;
48
52
@@ -52,6 +56,7 @@ export class ShadowRepo {
52
56
private packageDirs ! : NamedPackageDir [ ] ;
53
57
private status ! : StatusRow [ ] ;
54
58
private logger ! : Logger ;
59
+ private gitIgnoreLocations : string [ ] = [ ] ;
55
60
56
61
private constructor ( options : ShadowRepoOptions ) {
57
62
this . gitDir = getGitDir ( options . orgId , options . projectPath ) ;
@@ -84,6 +89,26 @@ export class ShadowRepo {
84
89
public async gitInit ( ) : Promise < void > {
85
90
await fs . promises . mkdir ( this . gitDir , { recursive : true } ) ;
86
91
await git . init ( { fs, dir : this . projectPath , gitdir : this . gitDir , defaultBranch : 'main' } ) ;
92
+ // set the forceIgnoreLocations so we only have to do it once
93
+ // this looks through
94
+ this . gitIgnoreLocations = (
95
+ ( await git . walk ( {
96
+ fs,
97
+ dir : this . projectPath ,
98
+ gitdir : this . gitDir ,
99
+ trees : [ git . WORKDIR ( ) ] ,
100
+ // TODO: this can be marginally faster if we limit it to pkgDirs and toplevel project files
101
+ // eslint-disable-next-line @typescript-eslint/require-await
102
+ map : async ( filepath : string ) => filepath ,
103
+ } ) ) as string [ ]
104
+ )
105
+ . filter (
106
+ ( filepath ) =>
107
+ filepath . includes ( gitIgnoreFileName ) &&
108
+ // can be top-level like '.' (no sep) OR must be in one of the package dirs
109
+ ( ! filepath . includes ( path . sep ) || this . packageDirs . some ( ( dir ) => pathIsInFolder ( filepath , dir . path ) ) )
110
+ )
111
+ . map ( ( ignoreFile ) => path . join ( this . projectPath , ignoreFile ) ) ;
87
112
}
88
113
89
114
/**
@@ -124,8 +149,13 @@ export class ShadowRepo {
124
149
dir : this . projectPath ,
125
150
gitdir : this . gitDir ,
126
151
filepaths,
127
- // filter out hidden files and __tests__ patterns, regardless of gitignore
128
- filter : ( f ) => ! f . includes ( `${ path . sep } .` ) && ! f . includes ( '__tests__' ) ,
152
+ // filter out hidden files and __tests__ patterns, regardless of gitignore, and the gitignore files themselves
153
+ filter : ( f ) =>
154
+ ! f . includes ( `${ path . sep } .` ) &&
155
+ ! f . includes ( '__tests__' ) &&
156
+ ! [ gitIgnoreFileName , stashedGitIgnoreFileName ] . includes ( path . basename ( f ) ) &&
157
+ // isogit uses `startsWith` for filepaths so it's possible to get a false positive
158
+ filepaths . some ( ( pkgDir ) => pathIsInFolder ( f , pkgDir , path . posix . sep ) ) ,
129
159
} ) ;
130
160
// isomorphic-git stores things in unix-style tree. Convert to windows-style if necessary
131
161
if ( isWindows ) {
@@ -246,18 +276,20 @@ export class ShadowRepo {
246
276
}
247
277
248
278
private async stashIgnoreFile ( ) : Promise < void > {
249
- const originalLocation = path . join ( this . projectPath , gitIgnoreFileName ) ;
250
- // another process may have already stashed the file
251
- if ( fs . existsSync ( originalLocation ) ) {
252
- await fs . promises . rename ( originalLocation , path . join ( this . projectPath , stashedGitIgnoreFileName ) ) ;
253
- }
279
+ // allSettled allows them to fail (example, the file wasn't where it was expected).
280
+ await Promise . allSettled (
281
+ this . gitIgnoreLocations . map ( ( originalLocation ) =>
282
+ fs . promises . rename ( originalLocation , originalLocation . replace ( gitIgnoreFileName , stashedGitIgnoreFileName ) )
283
+ )
284
+ ) ;
254
285
}
255
286
256
287
private async unStashIgnoreFile ( ) : Promise < void > {
257
- const stashedLocation = path . join ( this . projectPath , stashedGitIgnoreFileName ) ;
258
- // another process may have already un-stashed the file
259
- if ( fs . existsSync ( stashedLocation ) ) {
260
- await fs . promises . rename ( stashedLocation , path . join ( this . projectPath , gitIgnoreFileName ) ) ;
261
- }
288
+ // allSettled allows them to fail (example, the file wasn't where it was expected).
289
+ await Promise . allSettled (
290
+ this . gitIgnoreLocations . map ( ( originalLocation ) =>
291
+ fs . promises . rename ( originalLocation . replace ( gitIgnoreFileName , stashedGitIgnoreFileName ) , originalLocation )
292
+ )
293
+ ) ;
262
294
}
263
295
}
0 commit comments