Skip to content

Commit

Permalink
fix: add command-exists test to axioms for stability, moved from sync…
Browse files Browse the repository at this point in the history
… to async calls (todogroup#182)
  • Loading branch information
prototypicalpro authored Oct 2, 2020
1 parent ebca0b1 commit 0da11b9
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 39 deletions.
10 changes: 3 additions & 7 deletions axioms/licensee.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
const licensee = require('../lib/licensee')
const Result = require('../lib/result')

module.exports = function (fileSystem) {
module.exports = async function (fileSystem) {
let licenses = []
try {
licenses = licensee.identifyLicensesSync(fileSystem.targetDir)
licenses = await licensee.identifyLicense(fileSystem.targetDir)
} catch (error) {
if (error.message === 'Licensee not installed') {
return new Result('Licensee not found in path, only running license-independent rules', [], false)
} else {
return new Result(error.message, [], false)
}
return new Result(error.message, [], false)
}
return new Result('', licenses.map(l => { return { passed: true, path: l } }), true)
}
10 changes: 3 additions & 7 deletions axioms/linguist.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
const linguist = require('../lib/linguist')
const Result = require('../lib/result')

module.exports = function (fileSystem) {
module.exports = async function (fileSystem) {
const languages = []
try {
var jsonObj = linguist.identifyLanguagesSync(fileSystem.targetDir)
var jsonObj = await linguist.identifyLanguages(fileSystem.targetDir)
for (var language in jsonObj) {
languages.push(language.toLowerCase())
}
} catch (error) {
if (error.message === 'Linguist not installed') {
return new Result('Linguist not found in path, only running language-independent rules', [], false)
} else {
return new Result(error.message, [], false)
}
return new Result(error.message, [], false)
}
return new Result('', languages.map(l => { return { passed: true, path: l } }), true)
}
31 changes: 31 additions & 0 deletions lib/command_exists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const commandExistsLib = require('command-exists')

/**
* Checks whether or not a list of commands exists in the
* current environment. Returns the first command that was
* found to exist.
*
* @protected
* @param {string|string[]} command The command or commands to check for.
* @returns {string|null} The first command found to exist, or null of none were found.
*/
async function commandExists (command) {
// convert to array if needed
if (!Array.isArray(command)) {
command = [command]
}
for (const commandString of command) {
try {
await commandExistsLib(commandString)
return commandString
} catch (e) {
// do nothing
}
}
return null
}

module.exports.commandExists = commandExists
15 changes: 9 additions & 6 deletions lib/licensee.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018 TODO Group. All rights reserved.
// Licensed under the Apache License, Version 2.0.

const isWindows = require('is-windows')
const { commandExists } = require('./command_exists')
const spawnSync = require('child_process').spawnSync

class Licensee {
Expand All @@ -11,14 +11,17 @@ class Licensee {
* Throws 'Licensee not installed' error if command line of 'licensee' is not available.
*
* @param {string} targetDir The directory to run licensee on
* @returns {string[]} License identifiers
* @returns {Promise<string[]>} License identifiers
*/
identifyLicensesSync (targetDir) {
const licenseeOutput = spawnSync(isWindows() ? 'licensee.bat' : 'licensee', ['detect', '--json', targetDir]).stdout
if (licenseeOutput == null) {
async identifyLicense (targetDir) {
const command = await commandExists(['licensee', 'licensee.bat'])
if (command === null) {
throw new Error('Licensee not installed')
}

const licenseeOutput = spawnSync(command, ['detect', '--json', targetDir]).stdout
if (licenseeOutput == null) {
throw new Error('Error executing licensee')
}
const json = licenseeOutput.toString()
return JSON.parse(json).licenses.map(function (license) { return license.spdx_id })
}
Expand Down
22 changes: 12 additions & 10 deletions lib/linguist.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const isWindows = require('is-windows')
const spawnSync = require('child_process').spawnSync
const { commandExists } = require('./command_exists')

class Linguist {
/**
Expand All @@ -12,18 +12,20 @@ class Linguist {
* Throws 'Linguist not installed' error if command line of 'linguist' is not available.
*
* @param {string} targetDir The directory to run linguist on
* @returns {object} The linguist output
* @returns {Promise<object>} The linguist output
*/
identifyLanguagesSync (targetDir) {
async identifyLanguages (targetDir) {
// Command was renamed in https://github.com/github/linguist/pull/4208
for (const command of ['github-linguist', 'linguist']) {
const output = spawnSync(isWindows() ? `${command}.bat` : command, [targetDir, '--json']).stdout
if (output !== null) {
return JSON.parse(output.toString())
}
const command = await commandExists(['github-linguist', 'linguist', 'github-linguist.bat', 'linguist.bat'])
if (command === null) {
throw new Error('Linguist not installed')
}
const output = spawnSync(command, [targetDir, '--json']).stdout
if (output !== null) {
return JSON.parse(output.toString())
} else {
throw new Error('Execution of linguist failed!')
}

throw new Error('Linguist not installed')
}
}

Expand Down
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"dependencies": {
"ajv": "^6.12.4",
"chalk": "^4.1.0",
"command-exists": "^1.2.9",
"emoji-regex": "^9.0.0",
"eslint-config-standard": "^14.1.1",
"find-config": "^1.0.0",
Expand All @@ -63,7 +64,6 @@
"chai-as-promised": "^7.1.1",
"chai-each": "0.0.1",
"chai-string": "^1.5.0",
"command-exists": "^1.2.9",
"documentation": "^13.0.2",
"eslint": "^7.7.0",
"eslint-plugin-jsdoc": "^30.3.0",
Expand Down
8 changes: 4 additions & 4 deletions tests/axioms/licensee_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ describe('licensee', function () {
} else {
const licenseeAxiom = require('../../axioms/licensee')

it('runs licensee', () => {
it('runs licensee', async () => {
const mockFs = { targetDir: path.resolve(__dirname, '../../') }
const res = licenseeAxiom(mockFs)
const res = await licenseeAxiom(mockFs)

expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(1)
expect(res.targets[0].path).to.equal('Apache-2.0')
})

it('returns nothing if no licenses are found', () => {
it('returns nothing if no licenses are found', async () => {
const mockFs = { targetDir: path.resolve(__dirname) }
const res = licenseeAxiom(mockFs)
const res = await licenseeAxiom(mockFs)

expect(res.passed).to.equal(true)
expect(res.targets).to.have.length(0)
Expand Down
4 changes: 2 additions & 2 deletions tests/axioms/linguist_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ describe('linguist', function () {
} else {
const linguistAxiom = require('../../axioms/linguist')

it('runs linguist', () => {
it('runs linguist', async () => {
const mockFs = { targetDir: path.resolve(__dirname, '../../') }
const res = linguistAxiom(mockFs)
const res = await linguistAxiom(mockFs)

expect(res.passed).to.equal(true)
expect(res.targets).to.have.length.greaterThan(0)
Expand Down

0 comments on commit 0da11b9

Please sign in to comment.