Skip to content

Commit

Permalink
Merge pull request #63 from duhrer/GH-62
Browse files Browse the repository at this point in the history
Add ability to scan only staged files (resolves #62).
  • Loading branch information
amb26 authored Apr 17, 2024
2 parents e7707fb + 5d67e64 commit 76ff7b3
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 15 deletions.
7 changes: 7 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@
"env": {
"node": true,
"es6": true
},
"rules": {
"indent": [
"error",
4,
{ "SwitchCase": 1}
]
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"homepage": "https://github.com/fluid-project/fluid-lint-all",
"dependencies": {
"@prantlf/jsonlint": "11.7.0",
"@textlint/markdown-to-ast": "13.3.1",
"eslint": "8.53.0",
"eslint-config-fluid": "2.1.1-dev.20231104T144458Z.5488e1c.GH-17",
Expand All @@ -31,7 +32,6 @@
"infusion": "4.6.0",
"js-yaml": "4.1.0",
"json5": "2.2.3",
"@prantlf/jsonlint": "11.7.0",
"lintspaces": "0.10.2",
"markdownlint": "0.27.0",
"markdownlint-config-fluid": "0.1.4",
Expand All @@ -41,6 +41,7 @@
"stylelint-config-fluid": "0.2.1"
},
"devDependencies": {
"fs-extra": "^11.1.1",
"node-jqunit": "1.1.9"
}
}
4 changes: 2 additions & 2 deletions src/js/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ fluid.registerNamespace("fluid.lintAll");
*/
fluid.lintAll.parseArgs = function (processArgs) {
var minimistOptions = minimist(processArgs.slice(2), {
boolean: ["showMergedConfig", "showHelp", "showCheckedFiles"],
boolean: ["showMergedConfig", "showHelp", "showCheckedFiles", "stagedOnly"],
string: ["checks", "configFile"],
alias: {
"showHelp": ["h", "help"]
}
});

// Minimist only handles parsing and not validation, so we lightly validate the input here.
var supportedArgKeys = ["checks", "configFile", "showMergedConfig", "showHelp", "showCheckedFiles", "help", "h"];
var supportedArgKeys = ["checks", "configFile", "showMergedConfig", "stagedOnly", "showHelp", "showCheckedFiles", "help", "h"];
var argsOptions = fluid.filterKeys(minimistOptions, supportedArgKeys);
if (argsOptions.checks) {
argsOptions.checks = argsOptions.checks.trim().replace(/^"(.+)"$/, "$1").split(/ *, */);
Expand Down
10 changes: 8 additions & 2 deletions src/js/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fluid.defaults("fluid.lintAll.check", {
invokers: {
runChecks: {
funcName: "fluid.lintAll.runChecks",
args: ["{that}", "{arguments}.0"] // checksToRun
args: ["{that}", "{arguments}.0", "{arguments}.1"] // checksToRun, changedFiles
},
checkImpl: {
funcName: "fluid.notImplemented",
Expand All @@ -34,10 +34,11 @@ fluid.defaults("fluid.lintAll.check", {
*
* @param {Object} that - The `fluid.lintAll.check` component.
* @param {Array<String>} [checksToRun] - An optional list of checks to run. All checks are run if this is left out.
* @param {Array<String>} changedFiles - An array of paths to changed files, used to limit runs to uncommitted files.
* @return {CheckResults|Promise<CheckResults>} - The results of the check, which can either be a value for synchronous checks, or a `fluid.promise`.
*
*/
fluid.lintAll.runChecks = function (that, checksToRun) {
fluid.lintAll.runChecks = function (that, checksToRun, changedFiles) {
if (that.options.config.enabled && (!checksToRun || checksToRun.includes(that.options.key))) {
// Use fluid-glob to get the list of files.
var filesToScan = fluid.glob.findFiles(that.options.rootPath, that.options.config.includes, that.options.config.excludes, that.options.minimatchOptions);
Expand Down Expand Up @@ -71,7 +72,12 @@ fluid.lintAll.runChecks = function (that, checksToRun) {
});
}
}
}

if (changedFiles && changedFiles.length) {
filesToScan = filesToScan.filter(function (singlePath) {
return changedFiles.indexOf(singlePath) !== -1;
});
}

that.results.checked = filesToScan.length;
Expand Down
2 changes: 2 additions & 0 deletions src/js/launcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ function printUsageInstructions() {
" ",
" - showCheckedFiles: Display the list of files checked in the final output.",
" ",
" - stagedOnly: Only check files that have been staged for commit.",
" ",
" - checks: A command-delimited list of checks to run.",
" ",
" The following checks are supported:",
Expand Down
47 changes: 46 additions & 1 deletion src/js/lint-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var fs = require("fs");
var path = require("path");
var process = require("process");
var jsonlint = require("@prantlf/jsonlint");
var child_process = require("child_process");

require("json5/lib/register");

Expand Down Expand Up @@ -49,6 +50,7 @@ fluid.lintAll.runAllChecks = function (argsOptions) {
}

var checkRunner = fluid.lintAll.checkRunner({ userConfig: configFileOptions });

return checkRunner.runAllChecks(argsOptions);
};

Expand Down Expand Up @@ -408,9 +410,28 @@ fluid.lintAll.checkRunner.runAllChecks = function (that, argsOptions) {
fluid.log(fluid.logLevel.WARN, "fluid-lint-all: Running all checks.");
}

var stagedOnly = fluid.get(argsOptions, "stagedOnly");
var changedFiles = stagedOnly ? fluid.lintAll.getStagedFiles(that.options.config.rootPath) : [];

// This is checked in the integration tests, which cannot collect coverage data.
/* istanbul ignore if */
if (stagedOnly) {
fluid.log(fluid.logLevel.WARN, " (Scanning only files with uncommitted changes.)");
}

fluid.log(fluid.logLevel.WARN, "======================================================");
fluid.log(fluid.logLevel.WARN);

// This is checked in the integration tests, which cannot collect coverage data.
/* istanbul ignore if */
if (stagedOnly && !changedFiles.length) {
fluid.log(fluid.logLevel.WARN, "No files have been changed, skipping all checks...");
fluid.log(fluid.logLevel.WARN);

allChecksPromise.resolve();
return allChecksPromise;
}

if (argsOptions.showMergedConfig) {
var currentLogObjectRenderChars = fluid.logObjectRenderChars;
fluid.logObjectRenderChars = 100000;
Expand All @@ -421,7 +442,7 @@ fluid.lintAll.checkRunner.runAllChecks = function (that, argsOptions) {

fluid.visitComponentChildren(that, function (childComponent) {
if (fluid.componentHasGrade(childComponent, "fluid.lintAll.check")) {
var checkPromise = childComponent.runChecks(checkArgs);
var checkPromise = childComponent.runChecks(checkArgs, changedFiles);
checkPromises.push(checkPromise);
}
}, { flat: true });
Expand Down Expand Up @@ -456,3 +477,27 @@ fluid.lintAll.checkRunner.runAllChecks = function (that, argsOptions) {
}, allChecksPromise.reject); // TODO: Consider making this more forgiving.
return allChecksPromise;
};

fluid.lintAll.getStagedFiles = function (pathToCheck) {
var changedFiles = [];
var sanitisedRootPath = fluid.glob.sanitisePath(pathToCheck);

try {
// https://stackoverflow.com/questions/33610682/git-list-of-staged-files
var output = child_process.execSync("git diff --cached --name-only ", {
cwd: pathToCheck,
encoding: "utf-8"
});

var filePaths = output.trimStart().split("\n");

fluid.each(filePaths.slice(0, -1), function (filePath) {
changedFiles.push(sanitisedRootPath + "/" + filePath);
});
}
catch (error) {
fluid.log(error.stderr || error);
}

return changedFiles;
};
7 changes: 4 additions & 3 deletions src/js/rollup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fluid.defaults("fluid.lintAll.rollup", {
invokers: {
runChecks: {
funcName: "fluid.lintAll.rollup.runChecks",
args: ["{that}", "{arguments}.0"] // checksToRun
args: ["{that}", "{arguments}.0", "{arguments}.1"] // checksToRun, changedFiles
},
// We don't need the standard invoker used by standalone checks, but want to keep the data and other common bits.
checkImpl: {
Expand All @@ -29,15 +29,16 @@ fluid.defaults("fluid.lintAll.rollup", {
* @param {Object} that - The `fluid.lintAll.rollup` component.
* @param {Array<String>} [checksToRun] - An array of check "keys" indicating which checks should be run. If omitted,
* all checks are run.
* @param {Array<String>} changedFiles - An array of paths to changed files, used to limit runs to uncommitted files.
* @return {Promise <CheckResults>} - A promise that will resolve with the results of the check.
*
*/
fluid.lintAll.rollup.runChecks = function (that, checksToRun) {
fluid.lintAll.rollup.runChecks = function (that, checksToRun, changedFiles) {
var childResults = [];
fluid.visitComponentChildren(that, function (childComponent) {
if (fluid.componentHasGrade(childComponent, "fluid.lintAll.check")) {
if (!checksToRun || checksToRun.includes(childComponent.options.key) || checksToRun.includes(that.options.key)) {
var childResult = childComponent.runChecks();
var childResult = childComponent.runChecks(false, changedFiles);
childResults.push(childResult);
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/all-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

require("./js/args-tests");
require("./js/extractPosition-tests");
require("./js/git-tests.js");
require("./js/launcher-tests.js");
require("./js/lintAll-tests.js");
1 change: 1 addition & 0 deletions tests/fixtures/git/.fluidlintallrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
4 changes: 4 additions & 0 deletions tests/fixtures/git/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# "Changed Files" Test Fixture

This directory is used to test the "changed files" functionality (i.e.
`git status` integration).
3 changes: 3 additions & 0 deletions tests/fixtures/git/src/css/hidden.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.hidden {
display: none;
}
2 changes: 2 additions & 0 deletions tests/fixtures/git/src/js/nested/toMove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
// Intentionally empty but valid JS file.
1 change: 1 addition & 0 deletions tests/fixtures/git/src/js/toModify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"use strict";
3 changes: 3 additions & 0 deletions tests/fixtures/git/src/yaml/good.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
foo:
bar:
baz: qux
12 changes: 6 additions & 6 deletions tests/js/args-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,35 @@ var testDefs = {
noArgs: {
message: "We should be able to handle no arguments at all.",
args: [],
expected: { "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }
},
invalidArgs: {
message: "We should be able to handle invalid arguments.",
args: ["--stuff=nonsense", "--configFile=foo"],
errorKeys: ["stuff"],
expected: { configFile: "foo", "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { configFile: "foo", "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }
},
missingValues: {
message: "We should be able to handle missing argument values.",
args: ["--configFile", "--checks=foo"],
errorKeys: ["configFile"],
expected: { checks: ["foo"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { checks: ["foo"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }
},
checksArrayNoQuotes: {
message: "We should be able to handle a comma-delimited array of checks.",
args: ["--checks=foo,bar,baz"],
expected: { checks: ["foo", "bar", "baz"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { checks: ["foo", "bar", "baz"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }

},
checksQuotedArray: {
message: "We should be able to handle a quoted array of checks, including spaces.",
args: ["--checks=\"rice chex,corn chex, wheat chex ,pretzels,peanuts\""],
expected: { checks: ["rice chex", "corn chex", "wheat chex", "pretzels", "peanuts"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { checks: ["rice chex", "corn chex", "wheat chex", "pretzels", "peanuts"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }
},
checksSingleValue: {
message: "We should be able to handle missing argument values.",
args: ["--checks=blank"],
expected: { checks: ["blank"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false }
expected: { checks: ["blank"], "h": false, "help": false, showHelp: false, showMergedConfig: false, showCheckedFiles: false, stagedOnly: false }
}
};

Expand Down
Loading

0 comments on commit 76ff7b3

Please sign in to comment.