Skip to content

Commit

Permalink
feat: add file-remove fix (todogroup#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
prototypicalpro authored Oct 1, 2020
1 parent 45ee596 commit ee913b3
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 9 deletions.
24 changes: 17 additions & 7 deletions docs/fixes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Below is a complete list of fixes that Repolinter can run, along with their conf
- [Reference](#reference)
- [`file-create`](#file-create)
- [`file-modify`](#file-modify)
- [`file-remove`](#file-remove)

## Reference

Expand All @@ -25,10 +26,19 @@ Creates a file. Optionally removes or replaces files that failed.

Modify a file that failed a rule.

| Input | Required | Type | Default | Description |
| --------------------- | -------- | ---------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `text` | **Yes** | `string` \| `{ url: string }` \| `{ file: string }` | | The text to create the file with. Specify an object with the `url` or `file` property to pull text from a URL or file. |
| `files` | No | `string[]` | Failing files specified by the rule | A list of globs to modify files with. If this value is omitted, file-modify will instead target files that failed the rule. |
| `skip-paths-matching` | No | `{ extensions?: string[], patterns?: string[], flags?: string }` | `{}` | Use this option to exclude paths from `files`, either by file extension or by regular expression. |
| `write_mode` | No | `"prepend"` \| `"append"` | `"append"` | How file-modify should edit the file. |
| `newlines` | No | `{ begin?: number, end?: number }` | `{ begin: 0, end: 0 }` | How many newlines should be added to the start or end of `text`. This property allows formatters to print `text` without these newlines, creating a better user experience. |
| Input | Required | Type | Default | Description |
| --------------------- | -------- | ---------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text` | **Yes** | `string` \| `{ url: string }` \| `{ file: string }` | | The text to create the file with. Specify an object with the `url` or `file` property to pull text from a URL or file. |
| `files` | No | `string[]` | Failing files specified by the rule | A list of globs to modify files with. If this value is omitted, file-modify will instead target files that failed the rule. |
| `skip-paths-matching` | No | `{ extensions?: string[], patterns?: string[], flags?: string }` | `{}` | Use this option to exclude paths from `files`, either by file extension or by regular expression. |
| `write_mode` | No | `"prepend"` \| `"append"` | `"append"` | How file-modify should edit the file. |
| `newlines` | No | `{ begin?: number, end?: number }` | `{ begin: 0, end: 0 }` | How many newlines should be added to the start or end of `text`. This property allows formatters to print `text` without these newlines, creating a better user experience. |

### `file-remove`

Removes a file or files.

| Input | Required | Type | Default | Description |
| ---------- | -------- | ---------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `globsAll` | No | `string[]` | Failing files specified by the rule | The list of globs to remove files for. If this value is omitted, file-remove will instead target files that failed the rule. |
| `nocase` | No | `boolean` | `false` | Set to `true` to perform an case insensitive search with `globsAll`. |
12 changes: 12 additions & 0 deletions fixes/file-remove-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://raw.githubusercontent.com/todogroup/repolinter/master/fixes/file-remove-config.json",
"type": "object",
"properties": {
"globsAll": {
"type": "array",
"items": { "type": "string" }
},
"nocase": { "type": "boolean", "default": false }
}
}
35 changes: 35 additions & 0 deletions fixes/file-remove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const Result = require('../lib/result')
// eslint-disable-next-line no-unused-vars
const FileSystem = require('../lib/file_system')

/**
* Removes a file or a list of files.
*
* @param {FileSystem} fs A filesystem object configured with filter paths and target directories
* @param {object} options The rule configuration
* @param {string[]} targets The files to modify (will be overridden by options if present)
* @param {boolean} dryRun If true, repolinter will report suggested fixes, but will make no disk modifications.
* @returns {Promise<Result>} The fix result
*/
async function fileRemove (fs, options, targets, dryRun = false) {
// overwrite the targets with the files specified by options
if (options.globsAll && options.globsAll.length) {
targets = await fs.findAllFiles(options.globsAll, !!options.nocase)
}
// check that any targets exist
if (targets.length === 0) {
return new Result('Found no files to remove', [], false)
}
// remove the files
if (!dryRun) {
await Promise.all(targets.map(async t => fs.removeFile(t)))
}
// create a result
const removeTargets = targets.map(t => { return { passed: true, path: t, message: 'Remove file' } })
return new Result('', removeTargets, true)
}

module.exports = fileRemove
3 changes: 2 additions & 1 deletion fixes/fixes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

module.exports = [
'file-create',
'file-modify'
'file-modify',
'file-remove'
]
3 changes: 2 additions & 1 deletion rulesets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
"default": {},
"allOf": [
{ "if": { "properties": { "type": { "const": "file-modify" } } }, "then": { "properties": { "options": { "$ref": "../fixes/file-modify-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-create" } } }, "then": { "properties": { "options": { "$ref": "../fixes/file-create-config.json" } } } }
{ "if": { "properties": { "type": { "const": "file-create" } } }, "then": { "properties": { "options": { "$ref": "../fixes/file-create-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-remove" } } }, "then": { "properties": { "options": { "$ref": "../fixes/file-remove-config.json" } } } }
]
},
"policyInfo": { "type": "string" },
Expand Down
113 changes: 113 additions & 0 deletions tests/fixes/file_remove_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const chai = require('chai')
const expect = chai.expect

describe('fixes', () => {
describe('file-remove', () => {
const fileRemove = require('../../fixes/file-remove')

it('removes a file', async () => {
const removePaths = []
/** @type {any} */
const mockFs = {
removeFile (path) {
removePaths.push(path)
}
}

const res = await fileRemove(mockFs, {}, ['myfile'], false)
expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(1)
expect(res.targets[0].passed).to.equal(true)
expect(res.targets[0].path).to.equal('myfile')
expect(removePaths).to.deep.equal(['myfile'])
})

it('does nothing if dryRun is true', async () => {
const removePaths = []
/** @type {any} */
const mockFs = {
removeFile (path) {
removePaths.push(path)
}
}

const res = await fileRemove(mockFs, {}, ['myfile'], true)
expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(1)
expect(res.targets[0].passed).to.equal(true)
expect(res.targets[0].path).to.equal('myfile')
expect(removePaths).to.deep.equal([])
})

it('removes multiple files', async () => {
const removePaths = []
/** @type {any} */
const mockFs = {
removeFile (path) {
removePaths.push(path)
}
}

const res = await fileRemove(mockFs, {}, ['myfile', 'otherfile'], false)
expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(2)
expect(res.targets[0].passed).to.equal(true)
expect(res.targets[0].path).to.equal('myfile')
expect(res.targets[1].passed).to.equal(true)
expect(res.targets[1].path).to.equal('otherfile')
expect(removePaths).to.deep.equal(['myfile', 'otherfile'])
})

it('uses the glob option', async () => {
const removePaths = []
/** @type {any} */
const mockFs = {
removeFile (path) {
removePaths.push(path)
},
findAllFiles () {
return ['myfile.txt']
}
}

const res = await fileRemove(mockFs, { globsAll: ['myfile'] }, [], false)
expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(1)
expect(res.targets[0].passed).to.equal(true)
expect(res.targets[0].path).to.equal('myfile.txt')
expect(removePaths).to.deep.equal(['myfile.txt'])
})

it('overrides targets with the glob option', async () => {
const removePaths = []
/** @type {any} */
const mockFs = {
removeFile (path) {
removePaths.push(path)
},
findAllFiles () {
return ['myfile.txt']
}
}

const res = await fileRemove(mockFs, { globsAll: ['myfile'] }, ['otherfile'], false)
expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(1)
expect(res.targets[0].passed).to.equal(true)
expect(res.targets[0].path).to.equal('myfile.txt')
expect(removePaths).to.deep.equal(['myfile.txt'])
})

it('returns failure if no files are found', async () => {
/** @type {any} */
const mockFs = {}

const res = await fileRemove(mockFs, {}, [], false)
expect(res.passed).to.equal(false)
expect(res.targets).to.have.length(0)
})
})
})

0 comments on commit ee913b3

Please sign in to comment.