Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate a partial fence difference based on git changes since a provided oid #101

Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c19a51a
Add a file provider that avoids ts program walk
Aug 6, 2021
ddfefb1
progress -> progressBar
Aug 11, 2021
6bb301a
progress -> progressBar
Aug 11, 2021
525e910
Merge branch 'master' into u/mahuangh/faster-source-providers-3
Adjective-Object Aug 11, 2021
cce66e2
support definition files, simplify resolveImportsFromFile, exclude as…
Aug 11, 2021
ac076f2
getScriptFileExtensions
Aug 11, 2021
b012df6
add partial evaluation based on git checkout
Aug 11, 2021
6e181a2
remove FdirSourceFileProvider's dependencies
Aug 11, 2021
24a4fe6
remove looseRootFileDiscovery
Aug 11, 2021
c937ede
remove extra diff (fenceJobs -> normalizedFiles
Aug 11, 2021
155cf8f
add json to the moduleFileExtensions in jest
Aug 11, 2021
b90c25e
Added tests for getPartialCheck / getFenceDiff
Aug 12, 2021
e9b7322
add launch.json & debug current test
Aug 12, 2021
ff344ab
Prefer preProcessFile in getTsImportSetFromSourceString
Aug 12, 2021
8ba8b2a
consider tag diffs during partial evaluation
Aug 12, 2021
bae49ea
remove commented code from getTsImportSetFromSourceString
Aug 12, 2021
bdb73d7
update to new getScriptFIleExtensions from u/mahuangh/faster-source-p…
Aug 13, 2021
e7a2629
Merge remote-tracking branch 'upstream/master' into u/mahuangh/faster…
Aug 16, 2021
db855d8
get diffcount of index properly
Aug 17, 2021
ce3af4a
update log messages to replace -- with new sentences
Aug 17, 2021
8ad6d6d
remove errant \n in fenceless warnings
Aug 17, 2021
cb38bf2
Update runner.ts
smikula Aug 20, 2021
ad8ac8a
add new options to README
Aug 23, 2021
0eeea77
remove warning when skipping tag existence checks
Aug 23, 2021
d2148b7
avoid unecessary branch in runner.ts
Aug 23, 2021
dfba7db
null -> undefined in config.ts
Aug 23, 2021
1f95714
remove empty else branch
Aug 23, 2021
d9d0eeb
moving diff utils to utils/diffing
Aug 23, 2021
94d01f7
remove leftover cruft in diffing from previous refactors
Aug 23, 2021
81c71f4
check partialCheckLimit 'number' not 'boolean'
Aug 23, 2021
dc7fdf0
clarify comment on why we need to evaluate source files with changed …
Aug 23, 2021
2158ec3
move diffing tests to test/utils/diffing, and force a full recheck on…
Sep 1, 2021
dbe6a8f
clarifying comments around fenceDiff
Sep 1, 2021
c6048aa
Update warning message: removed tags section -> removed tags
Sep 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
// Use IntelliSense to learn about possible attributes.
Adjective-Object marked this conversation as resolved.
Show resolved Hide resolved
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "SingleTest",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
"args": ["--testPathPattern", "${fileBasenameNoExtension}"],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": null,
"runtimeArgs": ["--nolazy"],
"env": {
"NODE_ENV": "development"
},
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/src/**"],
"console": "integratedTerminal",
"skipFiles": [
"<node_internals>/**/*.js",
"${workspaceRoot}/node_modules/jest-*/**",
"${workspaceRoot}/node_modules/jsdom/**"
]
}
]
}
9 changes: 8 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
module.exports = {
testEnvironment: 'node',
moduleDirectories: ['node_modules'],
moduleFileExtensions: ['ts', 'js'],
moduleFileExtensions: [
'ts',
'js',
// nodegit parses its own package.json file,
// so we need this moduleFileExtension to be
// specified for tests.
'json',
],
transform: {
'.ts': '<rootDir>/jest.preprocessor.js',
},
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"commander": "^7.2.0",
"fdir": "^5.1.0",
"minimatch": "^3.0.4",
"nodegit": "^0.27.0",
"picomatch": "^2.3.0",
"tsconfig-paths": "^3.10.1",
"typescript": "^4.0.3"
Expand All @@ -28,6 +29,7 @@
"@types/commander": "^2.12.2",
"@types/jest": "^26.0.15",
"@types/node": "^12.7.8",
"@types/nodegit": "^0.27.2",
"husky": "^4.3.8",
"jest": "^26.6.0",
"prettier": "^2.2.1",
Expand Down
8 changes: 8 additions & 0 deletions src/core/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ async function main() {
.version(packageVersion)
.option('-p, --project <string> ', 'tsconfig.json file')
.option('-r, --rootDir <string...>', 'root directories of the project')
.option(
Adjective-Object marked this conversation as resolved.
Show resolved Hide resolved
'-g, --sinceGitHash <string>',
'Infer files and fences to check based on changes since the specified git hash'
)
.option(
'-l, --partialCheckLimit <number>',
'Maximum files to check during a partial check run. If more files than this limit are changed, the partial check will be aborted and good-fences will exit with code 0.'
)
.option(
'-x, --looseRootFileDiscovery',
'(UNSTABLE) Check source files under rootDirs instead of instantiating a full typescript program.'
Expand Down
4 changes: 2 additions & 2 deletions src/core/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ export function reportConfigError(message: string, configPath: string) {

export function reportWarning(message: string, configPath?: string) {
let fencePath = configPath + path.sep + 'fence.json';
let detailedMessage = `Good-fences warning: ${message}\n`;
let detailedMessage = `Good-fences warning: ${message}`;
if (configPath) {
detailedMessage += ` Fence: ${fencePath}`;
detailedMessage += `\n Fence: ${fencePath}`;
}

const warning: GoodFencesError = {
Expand Down
92 changes: 79 additions & 13 deletions src/core/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,27 @@ import getOptions, { setOptions } from '../utils/getOptions';
import validateFile from '../validation/validateFile';
import TypeScriptProgram from './TypeScriptProgram';
import normalizePath from '../utils/normalizePath';
import { getResult } from './result';
import { getResult, reportWarning } from './result';
import { validateTagsExist } from '../validation/validateTagsExist';
import { SourceFileProvider } from './SourceFileProvider';
import { FDirSourceFileProvider } from './FdirSourceFileProvider';
import NormalizedPath from '../types/NormalizedPath';
import { runWithConcurrentLimit } from '../utils/runWithConcurrentLimit';
import getConfigManager from '../utils/getConfigManager';
import { getFenceAndImportDiffsFromGit } from '../utils/getFenceAndImportDiffsFromGit';
import { getPartialCheckFromImportDiffs } from '../utils/getPartialCheckFromImportDiffs';
import * as path from 'path';
import { PartialCheck } from '../types/PartialCheck';

async function getPartialCheck(): Promise<PartialCheck> {
let options = getOptions();
if (options.sinceGitHash) {
const diffs = await getFenceAndImportDiffsFromGit(options.sinceGitHash);
if (diffs) {
return getPartialCheckFromImportDiffs(diffs);
}
}
}

async function getSourceFilesNormalized(
sourceFileProvider: SourceFileProvider,
Expand All @@ -24,24 +39,75 @@ export async function run(rawOptions: RawOptions) {
setOptions(rawOptions);
let options = getOptions();

let partialCheck = await getPartialCheck();
if (options.partialCheckLimit) {
if (!partialCheck) {
reportWarning(
`Skipping fence validation. Could not calculate a partial check, but partialCheckLimit was specified in options`
);
return getResult();
}
if (
partialCheck.fences.length + partialCheck.sourceFiles.length >
options.partialCheckLimit
) {
reportWarning(
`Skipping fence validation. The partial check had more than ${options.partialCheckLimit} changes`
);
return getResult();
}
}

let sourceFileProvider: SourceFileProvider = options.looseRootFileDiscovery
? new FDirSourceFileProvider(options.project, options.rootDir)
: new TypeScriptProgram(options.project);

// Do some sanity checks on the fences
validateTagsExist();
if (!partialCheck) {
// validating tags exist requires a full load of all fences
// we can't do this in partial check mode.
//
// Prefetching the full config set here avoids the overhead
// of partial fence loading, since we know we are loading
// the full fence set.
getConfigManager().getAllConfigs();
validateTagsExist();
} else {
reportWarning(
`skipping validateTagsExist. Cannot validate tag existence during partial checks`
Adjective-Object marked this conversation as resolved.
Show resolved Hide resolved
);
}

if (partialCheck) {
// validate only those files specified on the command line,
// or included in the scope of changed fence files.
const fenceScopeFiles = await getSourceFilesNormalized(
sourceFileProvider,
partialCheck.fences.map((fencePath: NormalizedPath) => path.dirname(fencePath))
);

const normalizedFiles = await getSourceFilesNormalized(sourceFileProvider);
const normalizedFiles = [...partialCheck.sourceFiles, ...fenceScopeFiles];

// Limit the concurrent executed promises because
// otherwise we will open all the files at the same time and
// hit the MFILE error (when we hit rlimit)
await runWithConcurrentLimit(
options.maxConcurrentFenceJobs,
normalizedFiles,
(normalizedFile: NormalizedPath) => validateFile(normalizedFile, sourceFileProvider),
options.progress
);
// we have to limit the concurrent executed promises because
// otherwise we will open all the files at the same time and
// hit the MFILE error (when we hit rlimit)
await runWithConcurrentLimit(
options.maxConcurrentFenceJobs,
normalizedFiles,
(normalizedFile: NormalizedPath) => validateFile(normalizedFile, sourceFileProvider),
options.progress
);
} else {
const normalizedFiles = await getSourceFilesNormalized(sourceFileProvider);

// we have to limit the concurrent executed promises because
// otherwise we will open all the files at the same time and
// hit the MFILE error (when we hit rlimit)
await runWithConcurrentLimit(
Adjective-Object marked this conversation as resolved.
Show resolved Hide resolved
options.maxConcurrentFenceJobs,
normalizedFiles,
(normalizedFile: NormalizedPath) => validateFile(normalizedFile, sourceFileProvider),
options.progress
);
}
return getResult();
}
2 changes: 2 additions & 0 deletions src/types/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export default interface Options {
project: NormalizedPath;
rootDir: NormalizedPath[];
ignoreExternalFences: boolean;
partialCheckLimit: number;
sinceGitHash?: string;
looseRootFileDiscovery: boolean;
// Maximum number of fence validation jobs that can
// be run at the same time.
Expand Down
6 changes: 6 additions & 0 deletions src/types/PartialCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import NormalizedPath from './NormalizedPath';

export type PartialCheck = {
fences: NormalizedPath[];
sourceFiles: NormalizedPath[];
};
2 changes: 2 additions & 0 deletions src/types/RawOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export default interface RawOptions {
project?: string;
rootDir?: string | string[];
ignoreExternalFences?: boolean;
sinceGitHash?: string;
partialCheckLimit?: number;
looseRootFileDiscovery?: boolean;
maxConcurrentJobs?: number;
progressBar?: boolean;
Expand Down
8 changes: 4 additions & 4 deletions src/types/config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import ExportRule from './ExportRule';

export default interface Config {
path: NormalizedPath;
tags: string[];
exports: ExportRule[];
dependencies: DependencyRule[];
imports: string[];
tags: string[] | null;
Adjective-Object marked this conversation as resolved.
Show resolved Hide resolved
exports: ExportRule[] | null;
dependencies: DependencyRule[] | null;
imports: string[] | null;
}
Loading