Skip to content

Commit

Permalink
feat: add file-not-exists rule (todogroup#183)
Browse files Browse the repository at this point in the history
* feat: add file-not-exists rule
  • Loading branch information
prototypicalpro authored Oct 1, 2020
1 parent ee913b3 commit ebca0b1
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 3 deletions.
13 changes: 13 additions & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Below is a complete list of rules that Repolinter can run, along with their conf
- [`file-existence`](#file-existence)
- [`file-hash`](#file-hash)
- [`file-not-contents`](#file-not-contents)
- [`file-not-exists`](#file-not-exists)
- [`file-starts-with`](#file-starts-with)
- [`file-type-exclusion`](#file-type-exclusion)
- [`git-grep-commits`](#git-grep-commits)
Expand Down Expand Up @@ -64,6 +65,7 @@ Checks the existence of a given file.
| -------------- | -------- | ---------- | ------- | -------------------------------------------------------------------------------------------------- |
| `globsAny` | **Yes** | `string[]` | | A list of globs to search for. This rule passes if at least one glob returns a file. |
| `nocase` | No | `boolean` | `false` | Set to `true` to perform an case insensitive search. |
| `dirs` | No | `boolean` | `false` | Set to `true` to include directories in the search (equivalent to `directory-exists`) |
| `fail-message` | No | `string` | `""` | The string to print if the directory does not exist, used to create human-readable error messages. |

### `file-hash`
Expand Down Expand Up @@ -91,6 +93,17 @@ Checks none of a given list of files match a given regular expression.
| `human-readable-content` | No | `string` | The regular expression in `content` | The string to print instead of the regular expression when generating human-readable output. |
| `fail-on-non-exist` | No | `boolean` | `false` | Set to `true` to disable passing if no files are found from `globsAll`. |

### `file-not-exists`

Checks that a file doesn't exist.

| Input | Required | Type | Default | Description |
| -------------- | -------- | ---------- | ------- | --------------------------------------------------------------------------------------------- |
| `globsAll` | **Yes** | `string[]` | | A list of globs to search for. This rule fails if at least one glob returns a file. |
| `nocase` | No | `boolean` | `false` | Set to `true` to perform an case insensitive search. |
| `dirs` | No | `boolean` | `false` | Set to `true` to include directories in the search. |
| `pass-message` | No | `string` | `""` | The string to print if the file does not exist, used to create human-readable error messages. |

### `file-starts-with`

Checks that the first lines of a file contain a set of regular expressions.
Expand Down
2 changes: 1 addition & 1 deletion rules/directory-existence.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

const fileExistence = require('./file-existence')
module.exports = function (fileSystem, opts) {
return fileExistence(fileSystem, Object.assign(opts, { dirs: true }))
return fileExistence(fileSystem, Object.assign({}, opts, { dirs: true }))
}
6 changes: 5 additions & 1 deletion rules/file-existence-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
"type": "array",
"items": { "type": "string" }
},
"fail-message": { "type": "string" }
"fail-message": { "type": "string" },
"dirs": {
"type": "boolean",
"default": false
}
},
"oneOf": [
{ "required": [ "globsAny" ] },
Expand Down
17 changes: 17 additions & 0 deletions rules/file-not-exists-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://raw.githubusercontent.com/todogroup/repolinter/master/rules/file-not-exists-config.json",
"type": "object",
"properties": {
"nocase": {
"type": "boolean",
"default": false
},
"globsAll": {
"type": "array",
"items": { "type": "string" }
},
"pass-message": { "type": "string" }
},
"required": ["globsAll"]
}
29 changes: 29 additions & 0 deletions rules/file-not-exists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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')

/**
* Check if a file is not present in the repository. Fails on the first file
* matching the glob pattern, succeeds if no file matching any of the patterns
* is found.
*
* @param {FileSystem} fs A filesystem object configured with filter paths and target directories
* @param {object} options The rule configuration
* @returns {Promise<Result>} The lint rule result
*/
async function fileNotExistence (fs, options) {
const fileList = options.globsAll
const file = options.dirs ? await fs.findAll(fileList, options.nocase) : await fs.findAllFiles(fileList, options.nocase)

return file.length !== 0
? new Result('Found files', file.map(f => { return { passed: false, path: f } }), false)
: new Result(
`${options['pass-message'] !== undefined ? options['pass-message'] + '. ' : ''}Did not find a file matching the specified patterns`,
fileList.map(f => { return { pattern: f, passed: true } }),
true)
}

module.exports = fileNotExistence
1 change: 1 addition & 0 deletions rules/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = [
'file-existence',
'file-hash',
'file-not-contents',
'file-not-exists',
'file-starts-with',
'file-type-exclusion',
'git-grep-commits',
Expand Down
1 change: 1 addition & 0 deletions rulesets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
{ "if": { "properties": { "type": { "const": "file-existence" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-existence-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-hash" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-hash-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-not-contents" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-not-contents-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-not-exists" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-not-exists-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-starts-with" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-starts-with-config.json" } } } },
{ "if": { "properties": { "type": { "const": "file-type-exclusion" } } }, "then": { "properties": { "options": { "$ref": "../rules/file-type-exclusion-config.json" } } } },
{ "if": { "properties": { "type": { "const": "git-grep-commits" } } }, "then": { "properties": { "options": { "$ref": "../rules/git-grep-commits-config.json" } } } },
Expand Down
3 changes: 3 additions & 0 deletions tests/axioms/contributor_count_test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const chai = require('chai')
const expect = chai.expect
const path = require('path')
Expand Down
3 changes: 3 additions & 0 deletions tests/cli/cli_tests.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const path = require('path')
const chai = require('chai')
const cp = require('child_process')
Expand Down
2 changes: 1 addition & 1 deletion tests/formatters/markdown_formatter_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('formatters', () => {

// console.debug(actual)
// console.debug(JSON.stringify(res))
expect(res.test).to.have.length(0)
expect(res.test).to.deep.equal([])
})

it('does not contain the string "undefined"', async function () {
Expand Down
94 changes: 94 additions & 0 deletions tests/rules/file_not_exists_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

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

describe('rule', () => {
describe('files_not_exists', () => {
const fileNotExists = require('../../rules/file-not-exists')

it('returns a passed result if no files exist', async () => {
/** @type {any} */
const mockfs = {
findAllFiles () {
return []
},
targetDir: '.'
}

const ruleopts = {
globsAll: ['LICENSE*']
}

const actual = await fileNotExists(mockfs, ruleopts)

expect(actual.passed).to.equal(true)
expect(actual.targets).to.have.length(1)
expect(actual.targets[0].pattern).to.equal(ruleopts.globsAll[0])
})

it('returns a passed result if no directories or files exist', async () => {
/** @type {any} */
const mockfs = {
findAll () {
return []
},
targetDir: '.'
}

const ruleopts = {
globsAll: ['LICENSE*'],
dirs: true
}

const actual = await fileNotExists(mockfs, ruleopts)

expect(actual.passed).to.equal(true)
expect(actual.targets).to.have.length(1)
expect(actual.targets[0].pattern).to.equal(ruleopts.globsAll[0])
})

it('returns a failure result if requested file exists', async () => {
/** @type {any} */
const mockfs = {
findAllFiles () {
return ['somefile']
},
targetDir: '.'
}

const ruleopts = {
globsAll: ['LICENSE*']
}

const actual = await fileNotExists(mockfs, ruleopts)

expect(actual.passed).to.equal(false)
expect(actual.targets).to.have.length(1)
expect(actual.targets[0]).to.deep.include({ passed: false, path: 'somefile' })
})

it('returns a pass result if requested file doesn\'t exist with a pass message', async () => {
/** @type {any} */
const mockfs = {
findAllFiles () {
return []
},
targetDir: '.'
}

const ruleopts = {
globsAll: ['LICENSE*'],
'pass-message': 'The license file should exist.'
}

const actual = await fileNotExists(mockfs, ruleopts)

expect(actual.passed).to.equal(true)
expect(actual.targets).to.have.length(1)
expect(actual.targets[0].pattern).to.equal(ruleopts.globsAll[0])
expect(actual.message).to.contain(ruleopts['pass-message'])
})
})
})

0 comments on commit ebca0b1

Please sign in to comment.