Skip to content

Commit

Permalink
Add tool version changes as incremental rebuild trigger (#16200)
Browse files Browse the repository at this point in the history
For tsc, add a version check with the tsBuildInfo file to trigger
incremental rebuild trigger.
For the following tools, add the tool version in the done log files to
serve as an incremental rebuild trigger when it changes.
- api-extractor
- tslint
- eslint
- prettier

Fixes
[AB#4809](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/4809)
  • Loading branch information
curtisman authored Jun 30, 2023
1 parent b5e1e29 commit d061f18
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 6 deletions.
1 change: 0 additions & 1 deletion build-tools/packages/build-tools/src/common/npmPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import * as chalk from "chalk";
import detectIndent from "detect-indent";
import * as fs from "fs";
import { readFileSync, readJsonSync, writeJsonSync } from "fs-extra";
import { sync as globSync, hasMagic } from "glob";
import * as path from "path";
import sortPackageJson from "sort-package-json";

Expand Down
15 changes: 15 additions & 0 deletions build-tools/packages/build-tools/src/common/taskUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
import * as path from "path";
import { existsSync } from "fs";
import { lookUpDirSync, readFileAsync } from "./utils";

export function getEsLintConfigFilePath(dir: string) {
// TODO: we currently don't support .yaml and .yml, or config in package.json
Expand All @@ -16,3 +17,17 @@ export function getEsLintConfigFilePath(dir: string) {
}
return undefined;
}

export async function getInstalledPackageVersion(packageName: string, cwd: string) {
const resolvedPath = require.resolve(packageName, { paths: [cwd] });
const packageJsonPath = await lookUpDirSync(resolvedPath, (currentDir) => {
return existsSync(path.join(currentDir, "package.json"));
});
if (packageJsonPath === undefined) {
throw new Error(`Unable to find package ${packageName} from ${cwd}`);
}
const packageJson = JSON.parse(
await readFileAsync(path.join(packageJsonPath, "package.json"), "utf8"),
);
return packageJson.version;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/
import { getInstalledPackageVersion } from "../../../common/taskUtils";
import { TscDependentTask } from "./tscTask";

export class ApiExtractorTask extends TscDependentTask {
protected get configFileFullPath() {
return this.getPackageFileFullPath("api-extractor.json");
}

protected async getToolVersion() {
return getInstalledPackageVersion("@microsoft/api-extractor", this.node.pkg.directory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/
import { getEsLintConfigFilePath } from "../../../common/taskUtils";
import { getEsLintConfigFilePath, getInstalledPackageVersion } from "../../../common/taskUtils";
import { TscDependentTask } from "./tscTask";

export class TsLintTask extends TscDependentTask {
protected get configFileFullPath() {
return this.getPackageFileFullPath("tslint.json");
}

protected async getToolVersion() {
return getInstalledPackageVersion("tslint", this.node.pkg.directory);
}
}

export class EsLintTask extends TscDependentTask {
Expand All @@ -30,4 +34,8 @@ export class EsLintTask extends TscDependentTask {
}
return false;
}

protected async getToolVersion() {
return getInstalledPackageVersion("eslint", this.node.pkg.directory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import * as path from "path";

import { existsSync, globFn, readFileAsync, statAsync } from "../../../common/utils";
import { BuildPackage } from "../../buildGraph";
import { LeafTask, LeafWithDoneFileTask } from "./leafTask";
import { LeafWithDoneFileTask } from "./leafTask";
import { getInstalledPackageVersion } from "../../../common/taskUtils";

export class PrettierTask extends LeafWithDoneFileTask {
private parsed: boolean = false;
Expand Down Expand Up @@ -104,7 +105,10 @@ export class PrettierTask extends LeafWithDoneFileTask {
return { name, hash };
});
const hashes = await Promise.all(hashesP);
return JSON.stringify(hashes);
return JSON.stringify({
version: await getInstalledPackageVersion("prettier", this.node.pkg.directory),
hashes,
});
} catch (e) {
this.traceExec(`error generating done file content. ${e}`);
return undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as ts from "typescript";

import { defaultLogger } from "../../../common/logging";
import { existsSync, readFileAsync } from "../../../common/utils";
import { getInstalledPackageVersion } from "../../../common/taskUtils";
import * as TscUtils from "../../../common/tscUtils";
import { LeafTask, LeafWithDoneFileTask } from "./leafTask";

Expand All @@ -23,6 +24,7 @@ interface ITsBuildInfo {
semanticDiagnosticsPerFile?: any[];
options: any;
};
version: string;
}

export class TscTask extends LeafTask {
Expand Down Expand Up @@ -103,6 +105,22 @@ export class TscTask extends LeafTask {
this.traceTrigger(`new file detected ${[...configFileNames.values()].join(",")}`);
return false;
}
try {
const tsVersion = await getInstalledPackageVersion(
"typescript",
this.node.pkg.directory,
);

if (tsVersion !== tsBuildInfo.version) {
this.traceTrigger("previous build error");
return false;
}
} catch (e) {
this.traceTrigger(
`Unable to get installed package version for typescript from ${this.node.pkg.directory}`,
);
return false;
}

// Check tsconfig.json
return this.checkTsConfig(tsBuildInfoFileDirectory, tsBuildInfo, config);
Expand Down Expand Up @@ -384,11 +402,16 @@ export abstract class TscDependentTask extends LeafWithDoneFileTask {
config = await readFileAsync(this.configFileFullPath, "utf8");
}

return JSON.stringify({ tsBuildInfoFiles, config });
return JSON.stringify({
version: await this.getToolVersion(),
config,
tsBuildInfoFiles,
});
} catch (e) {
this.traceExec(`error generating done file content ${e}`);
return undefined;
}
}
protected abstract get configFileFullPath(): string;
protected abstract getToolVersion(): Promise<string>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import type { WorkerExecResult, WorkerMessage } from "./worker";
export async function compile(msg: WorkerMessage): Promise<WorkerExecResult> {
const { command, cwd } = msg;
// Load the typescript version that is in the cwd scope
// Load the eslint version that is in the cwd scope
const tsPath = require.resolve("typescript", { paths: [cwd] });
const ts: typeof tsLib = require(tsPath);

Expand Down

0 comments on commit d061f18

Please sign in to comment.