Skip to content

Commit

Permalink
feat: add --force and statusMatrix --ignored (isomorphic-git#1519)
Browse files Browse the repository at this point in the history
* feat: add --force and statusMatrix --ignored

* style: lint --fix

* fix: optional property on jsdoc for TS

* refactor: pr feedback
  • Loading branch information
mshanemc authored Mar 21, 2022
1 parent 2e09b91 commit 080497f
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 23 deletions.
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach to Remote",
"address": "localhost",
"port": 9229,
"skipFiles": ["<node_internals>/**/*.js"]
},
]
}
37 changes: 35 additions & 2 deletions __tests__/test-add.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,22 @@ describe('add', () => {
dir,
filepath: ['a.txt', 'i.txt'],
})
expect((await listFiles({ fs, dir })).length).toEqual(1)
expect(await listFiles({ fs, dir })).toEqual(['a.txt'])
})
it('multiple files with 1 ignored and force:true', async () => {
// Setup
const { fs, dir } = await makeFixture('test-add')
await writeGitIgnore(fs, dir)

// Test
await init({ fs, dir })
await add({
fs,
dir,
filepath: ['a.txt', 'i.txt'],
force: true,
})
expect((await listFiles({ fs, dir })).length).toEqual(2)
expect(await listFiles({ fs, dir })).toEqual(['a.txt', 'i.txt'])
})
it('symlink', async () => {
// Setup
Expand Down Expand Up @@ -136,6 +150,15 @@ describe('add', () => {
await add({ fs, dir, filepath: 'i.txt' })
expect((await listFiles({ fs, dir })).length).toEqual(0)
})
it('ignored file but with force=true', async () => {
// Setup
const { fs, dir } = await makeFixture('test-add')
await writeGitIgnore(fs, dir)
// Test
await init({ fs, dir })
await add({ fs, dir, filepath: 'i.txt', force: true })
expect((await listFiles({ fs, dir })).length).toEqual(1)
})
it('non-existant file', async () => {
// Setup
const { fs, dir } = await makeFixture('test-add')
Expand Down Expand Up @@ -168,6 +191,16 @@ describe('add', () => {
await add({ fs, dir, filepath: 'c' })
expect((await listFiles({ fs, dir })).length).toEqual(3)
})
it('folder with .gitignore and force', async () => {
// Setup
const { fs, dir } = await makeFixture('test-add')
await writeGitIgnore(fs, dir)
// Test
await init({ fs, dir })
expect((await listFiles({ fs, dir })).length).toEqual(0)
await add({ fs, dir, filepath: 'c', force: true })
expect((await listFiles({ fs, dir })).length).toEqual(4)
})
it('git add .', async () => {
// Setup
const { fs, dir } = await makeFixture('test-add')
Expand Down
189 changes: 189 additions & 0 deletions __tests__/test-statusMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,195 @@ describe('statusMatrix', () => {
expect(a).toEqual([['.gitignore', 0, 2, 2]])
})

it('does not return ignored files already in the index', async () => {
// Setup
const { fs, dir, gitdir } = await makeFixture('test-empty')
await fs.write(path.join(dir, '.gitignore'), 'ignoreme.txt\n')
await add({ fs, dir, gitdir, filepath: '.' })
await fs.write(path.join(dir, 'ignoreme.txt'), 'ignored')

// Test
const a = await statusMatrix({ fs, dir, gitdir })
expect(a).toEqual([['.gitignore', 0, 2, 2]])
})

it('returns ignored files already in the index if ignored:true', async () => {
// Setup
const { fs, dir, gitdir } = await makeFixture('test-empty')
await fs.write(path.join(dir, '.gitignore'), 'ignoreme.txt\n')
await add({ fs, dir, gitdir, filepath: '.' })
await fs.write(path.join(dir, 'ignoreme.txt'), 'ignored')

// Test
const a = await statusMatrix({ fs, dir, gitdir, ignored: true })
expect(a).toEqual([
['.gitignore', 0, 2, 2],
['ignoreme.txt', 0, 2, 0],
])
})

it('ignored:true works with multiple added files ', async () => {
// Setup
const { fs, dir, gitdir } = await makeFixture('test-empty')
await fs.write(
path.join(dir, '.gitignore'),
'ignoreme.txt\nignoreme2.txt\n'
)
await add({ fs, dir, gitdir, filepath: '.' })
await fs.write(path.join(dir, 'ignoreme.txt'), 'ignored')
await fs.write(path.join(dir, 'ignoreme2.txt'), 'ignored')

// Test
const a = await statusMatrix({ fs, dir, gitdir, ignored: true })
expect(a).toEqual([
['.gitignore', 0, 2, 2],
['ignoreme.txt', 0, 2, 0],
['ignoreme2.txt', 0, 2, 0],
])
})

describe('ignored:true works supports multiple filepaths', () => {
let fs, dir, gitdir
const ignoredFolder = 'ignoreThisFolder'
const nonIgnoredFolder = 'nonIgnoredFolder'

beforeAll(async () => {
// Setup
const output = await makeFixture('test-empty')
fs = output.fs
dir = output.dir
gitdir = output.gitdir

await fs.write(path.join(dir, '.gitignore'), `${ignoredFolder}/*\n`)
await add({ fs, dir, gitdir, filepath: '.' })
await fs.mkdir(path.join(dir, ignoredFolder))
await fs.mkdir(path.join(dir, nonIgnoredFolder))
await fs.write(
path.join(dir, nonIgnoredFolder, 'notIgnored.txt'),
'notIgnored'
)
await fs.write(path.join(dir, ignoredFolder, 'ignoreme.txt'), 'ignored')
await fs.write(path.join(dir, 'notIgnored.txt'), 'notIgnored')
})

it('base case: no filepaths', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
ignored: true,
})
expect(result).toEqual([
['.gitignore', 0, 2, 2],
[`${ignoredFolder}/ignoreme.txt`, 0, 2, 0],
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})

it('filepaths on ignored folder should return empty', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: [ignoredFolder],
})
expect(result).toEqual([])
})

it('shows nonignored file and folder', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: [ignoredFolder, 'notIgnored.txt', nonIgnoredFolder],
})
expect(result).toEqual([
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})

it('filepaths on ignored folder and non-ignored file should show all files with ignored:true ', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: [ignoredFolder, 'notIgnored.txt', nonIgnoredFolder],
ignored: true,
})
expect(result).toEqual([
[`${ignoredFolder}/ignoreme.txt`, 0, 2, 0],
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})

describe('all files, ignored:true, test order permutation', () => {
it('file, ignored, notignored', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: ['notIgnored.txt', ignoredFolder, nonIgnoredFolder],
ignored: true,
})
expect(result).toEqual([
[`${ignoredFolder}/ignoreme.txt`, 0, 2, 0],
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})
it('ignored, notignored, file', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: [ignoredFolder, nonIgnoredFolder, 'notIgnored.txt'],
ignored: true,
})
expect(result).toEqual([
[`${ignoredFolder}/ignoreme.txt`, 0, 2, 0],
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})
it('notignored, ignored, file', async () => {
const result = await statusMatrix({
fs,
dir,
gitdir,
filepaths: [nonIgnoredFolder, ignoredFolder, 'notIgnored.txt'],
ignored: true,
})
expect(result).toEqual([
[`${ignoredFolder}/ignoreme.txt`, 0, 2, 0],
[`${nonIgnoredFolder}/notIgnored.txt`, 0, 2, 0],
['notIgnored.txt', 0, 2, 0],
])
})
})
})
it('ignored: true has no impact when file is already in index', async () => {
// Setup
const { fs, dir, gitdir } = await makeFixture('test-empty')
await fs.write(path.join(dir, '.gitignore'), 'ignoreme.txt\n')
await fs.write(path.join(dir, 'ignoreme.txt'), 'ignored')
await add({ fs, dir, gitdir, filepath: '.', force: true })
// Test
const a = await statusMatrix({ fs, dir, gitdir, ignored: true })
expect(a).toEqual([
['.gitignore', 0, 2, 2],
['ignoreme.txt', 0, 2, 2],
])
// Test
const b = await statusMatrix({ fs, dir, gitdir, ignored: false })
expect(b).toEqual([
['.gitignore', 0, 2, 2],
['ignoreme.txt', 0, 2, 2],
])
})

it('statusMatrix with filepaths', async () => {
// Setup
const { fs, dir, gitdir } = await makeFixture('test-statusMatrix-filepath')
Expand Down
23 changes: 14 additions & 9 deletions src/api/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { join } from '../utils/join.js'
* @param {string} [args.gitdir=join(dir, '.git')] - [required] The [git directory](dir-vs-gitdir.md) path
* @param {string|string[]} args.filepath - The path to the file to add to the index
* @param {object} [args.cache] - a [cache](cache.md) object
* @param {boolean} [args.force=false] - add to index even if matches gitignore. Think `git add --force`
*
* @returns {Promise<void>} Resolves successfully once the git index has been updated
*
Expand All @@ -34,6 +35,7 @@ export async function add({
gitdir = join(dir, '.git'),
filepath,
cache = {},
force = false,
}) {
try {
assertParameter('fs', _fs)
Expand All @@ -43,25 +45,27 @@ export async function add({

const fs = new FileSystem(_fs)
await GitIndexManager.acquire({ fs, gitdir, cache }, async index => {
return addToIndex({ dir, gitdir, fs, filepath, index })
return addToIndex({ dir, gitdir, fs, filepath, index, force })
})
} catch (err) {
err.caller = 'git.add'
throw err
}
}

async function addToIndex({ dir, gitdir, fs, filepath, index }) {
async function addToIndex({ dir, gitdir, fs, filepath, index, force }) {
// TODO: Should ignore UNLESS it's already in the index.
filepath = Array.isArray(filepath) ? filepath : [filepath]
const promises = filepath.map(async currentFilepath => {
const ignored = await GitIgnoreManager.isIgnored({
fs,
dir,
gitdir,
filepath: currentFilepath,
})
if (ignored) return
if (!force) {
const ignored = await GitIgnoreManager.isIgnored({
fs,
dir,
gitdir,
filepath: currentFilepath,
})
if (ignored) return
}
const stats = await fs.lstat(join(dir, currentFilepath))
if (!stats) throw new NotFoundError(currentFilepath)

Expand All @@ -74,6 +78,7 @@ async function addToIndex({ dir, gitdir, fs, filepath, index }) {
fs,
filepath: [join(currentFilepath, child)],
index,
force,
})
)
await Promise.all(promises)
Expand Down
11 changes: 7 additions & 4 deletions src/api/statusMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ import { worthWalking } from '../utils/worthWalking.js'
* @param {string[]} [args.filepaths = ['.']] - Limit the query to the given files and directories
* @param {function(string): boolean} [args.filter] - Filter the results to only those whose filepath matches a function.
* @param {object} [args.cache] - a [cache](cache.md) object
* @param {boolean} [args.ignored = false] - include ignored files in the result
*
* @returns {Promise<Array<StatusRow>>} Resolves with a status matrix, described below.
* @see StatusRow
Expand All @@ -159,6 +160,7 @@ export async function statusMatrix({
filepaths = ['.'],
filter,
cache = {},
ignored: shouldIgnore = false,
}) {
try {
assertParameter('fs', _fs)
Expand All @@ -175,14 +177,15 @@ export async function statusMatrix({
map: async function(filepath, [head, workdir, stage]) {
// Ignore ignored files, but only if they are not already tracked.
if (!head && !stage && workdir) {
if (
await GitIgnoreManager.isIgnored({
if (!shouldIgnore) {
const isIgnored = await GitIgnoreManager.isIgnored({
fs,
dir,
filepath,
})
) {
return null
if (isIgnored) {
return null
}
}
}
// match against base paths
Expand Down
17 changes: 9 additions & 8 deletions website/versioned_docs/version-1.x/add.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ original_id: add

Add a file to the git index (aka staging area)

| param | type [= default] | description |
| -------------- | ------------------------------- | --------------------------------------------------------- |
| [**fs**](./fs) | FsClient | a file system implementation |
| **dir** | string | The [working tree](dir-vs-gitdir.md) directory path |
| **gitdir** | string = join(dir, '.git') | The [git directory](dir-vs-gitdir.md) path |
| **filepath** | string &#124; Array\<string\> | The path to the file to add to the index |
| cache | object | a [cache](cache.md) object |
| return | Promise\<void\> | Resolves successfully once the git index has been updated |
| param | type [= default] | description |
| -------------- | ------------------------------- | --------------------------------------------------------------- |
| [**fs**](./fs) | FsClient | a file system implementation |
| **dir** | string | The [working tree](dir-vs-gitdir.md) directory path |
| **gitdir** | string = join(dir, '.git') | The [git directory](dir-vs-gitdir.md) path |
| **filepath** | string &#124; Array\<string\> | The path to the file to add to the index |
| cache | object | a [cache](cache.md) object |
| **force** | boolean | add to index even if matches gitignore. Think `git add --force` |
| return | Promise\<void\> | Resolves successfully once the git index has been updated |

Example Code:

Expand Down
1 change: 1 addition & 0 deletions website/versioned_docs/version-1.x/statusMatrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Efficiently get the status of multiple files at once.
| filepaths | Array\<string\> = ['.'] | Limit the query to the given files and directories |
| filter | function(string): boolean | Filter the results to only those whose filepath matches a function. |
| cache | object | a [cache](cache.md) object |
| ignored | boolean | include ignored files in the result |
| return | Promise\<Array\<StatusRow\>\> | Resolves with a status matrix, described below. |

```ts
Expand Down

0 comments on commit 080497f

Please sign in to comment.