Skip to content

Commit 0d208d3

Browse files
yzx9carloscuesta
andauthored
✨ Searching config in ancestor directories (#1422)
* ✨ Searching config in ancestor directories * βœ… Add tests for searching config * πŸ“ Update README.md --------- Co-authored-by: Carlos Cuesta <carloscuesta@me.com>
1 parent 8e2e560 commit 0d208d3

File tree

3 files changed

+120
-7
lines changed

3 files changed

+120
-7
lines changed

β€ŽREADME.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ You can configure these options via (in order of precedence):
136136

137137
- A `gitmoji` key in your `package.json` file
138138
- A `.gitmojirc.json` file.
139+
- A `gitmoji` key in a package.json file in a parent directory (recursively)
140+
- A `.gitmojirc.json` file in a parent directory (recursively)
139141
- Using the global cli configuration.
140142

141143
If no user configuration is found, a set of default values will be used.

β€Žsrc/utils/configurationVault/getConfiguration.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Conf from 'conf'
22
import { cwd } from 'process'
33
import { readFileSync } from 'fs'
4+
import { dirname } from 'path'
45
import { pathExistsSync } from 'path-exists'
56

67
import { CONFIG, EMOJI_COMMIT_FORMATS } from '@constants/configuration'
@@ -60,15 +61,21 @@ const getConfiguration = (): { get: Function, set: Function } => {
6061
const loadConfig = (): {
6162
[$Values<typeof CONFIG>]: string | boolean
6263
} => {
63-
const packageJson = `${cwd()}/package.json`
64-
const configurationFile = `${cwd()}/.gitmojirc.json`
64+
let currentDir = cwd()
6565

66-
if (pathExistsSync(packageJson) && getFile(packageJson)?.gitmoji) {
67-
return getFile(packageJson)?.gitmoji
68-
}
66+
while (currentDir !== dirname(currentDir)) {
67+
const packageJson = `${currentDir}/package.json`
68+
const configurationFile = `${currentDir}/.gitmojirc.json`
69+
70+
if (pathExistsSync(packageJson) && getFile(packageJson)?.gitmoji) {
71+
return getFile(packageJson)?.gitmoji
72+
}
73+
74+
if (pathExistsSync(configurationFile) && getFile(configurationFile)) {
75+
return getFile(configurationFile)
76+
}
6977

70-
if (pathExistsSync(configurationFile) && getFile(configurationFile)) {
71-
return getFile(configurationFile)
78+
currentDir = dirname(currentDir)
7279
}
7380

7481
return LOCAL_CONFIGURATION.store

β€Žtest/utils/configurationVault/getConfiguration.spec.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,110 @@ describe('getConfiguration', () => {
129129
})
130130
})
131131

132+
describe('when config exists in parent directory', () => {
133+
const originalCwd = process.cwd
134+
135+
beforeEach(() => {
136+
jest.resetModules()
137+
})
138+
139+
beforeAll(() => {
140+
process.cwd = jest.fn(() => '/home/user/project/subfolder')
141+
142+
pathExistsSync.mockImplementation((path) => {
143+
return path.includes('/home/user/project/.gitmojirc.json')
144+
})
145+
146+
readFileSync.mockImplementation((path) => {
147+
if (path.includes('/home/user/project/.gitmojirc.json')) {
148+
return JSON.stringify({ from: 'parent' })
149+
}
150+
return ''
151+
})
152+
})
153+
154+
afterAll(() => {
155+
process.cwd = originalCwd
156+
})
157+
158+
it('should load config from parent directory', () => {
159+
const configuration = getConfiguration()
160+
expect(configuration.get('from')).toEqual('parent')
161+
})
162+
})
163+
164+
describe('when config exists in grandparent directory', () => {
165+
const originalCwd = process.cwd
166+
167+
beforeEach(() => {
168+
jest.resetModules()
169+
})
170+
171+
beforeAll(() => {
172+
process.cwd = jest.fn(() => '/home/user/project/subfolder')
173+
174+
pathExistsSync.mockImplementation((path) => {
175+
return path.includes('/home/user/.gitmojirc.json')
176+
})
177+
178+
readFileSync.mockImplementation((path) => {
179+
if (path.includes('/home/user/.gitmojirc.json')) {
180+
return JSON.stringify({ from: 'grandparent' })
181+
}
182+
return ''
183+
})
184+
})
185+
186+
afterAll(() => {
187+
process.cwd = originalCwd
188+
})
189+
190+
it('should load config from grandparent directory', () => {
191+
const configuration = getConfiguration()
192+
expect(configuration.get('from')).toEqual('grandparent')
193+
})
194+
})
195+
196+
describe('when config exists in current and parent directory', () => {
197+
const originalCwd = process.cwd
198+
199+
beforeEach(() => {
200+
jest.resetModules()
201+
})
202+
203+
beforeAll(() => {
204+
process.cwd = jest.fn(() => '/home/user/project/subfolder')
205+
206+
pathExistsSync.mockImplementation((path) => {
207+
return (
208+
path.includes('/home/user/project/subfolder/.gitmojirc.json') ||
209+
path.includes('/home/user/project/.gitmojirc.json')
210+
)
211+
})
212+
213+
readFileSync.mockImplementation((path) => {
214+
if (path.includes('/home/user/project/subfolder/.gitmojirc.json')) {
215+
return JSON.stringify({ from: 'current' })
216+
}
217+
218+
if (path.includes('/home/user/project/.gitmojirc.json')) {
219+
return JSON.stringify({ from: 'parent' })
220+
}
221+
222+
return ''
223+
})
224+
})
225+
226+
afterAll(() => {
227+
process.cwd = originalCwd
228+
})
229+
230+
it('should prefer config from current directory over parent', () => {
231+
const configuration = getConfiguration()
232+
expect(configuration.get('from')).toEqual('current')
233+
})
234+
})
235+
132236
describe('when package.json and .gitmojirc are not available', () => {
133237
beforeAll(() => {
134238
pathExistsSync.mockReturnValue(false)

0 commit comments

Comments
Β (0)