Skip to content
This repository has been archived by the owner on Jun 11, 2020. It is now read-only.

For dependent packages, only test against typescript@next #398

Merged
1 commit merged into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions src/check-parse-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default async function main(includeNpmChecks: boolean, options: Options):
const allPackages = await AllPackages.read(options);
const [log, logResult] = logger();

checkTypeScriptVersions(allPackages);

checkPathMappings(allPackages);

const packages = allPackages.allPackages();
Expand Down Expand Up @@ -50,6 +52,16 @@ function checkForDuplicates(packages: ReadonlyArray<AnyPackage>, func: (info: An
}
}

function checkTypeScriptVersions(allPackages: AllPackages): void {
for (const pkg of allPackages.allTypings()) {
for (const dep of allPackages.allDependencyTypings(pkg)) {
if (dep.typeScriptVersion > pkg.typeScriptVersion) {
throw new Error(`${pkg.desc} depends on ${dep.desc} but has a lower required TypeScript version.`);
}
}
}
}

function checkPathMappings(allPackages: AllPackages): void {
for (const pkg of allPackages.allTypings()) {
const pathMappings = new Map(pkg.pathMappings);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/module-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ export async function getTestDependencies(pkgName: string, directory: string, te
}

for (const imported of imports(sourceFile)) {
if (!imported.startsWith(".") && !dependencies.has(imported)) {
if (!imported.startsWith(".") && !dependencies.has(imported) && imported !== pkgName) {
testDependencies.add(imported);
}
}
Expand Down
17 changes: 11 additions & 6 deletions src/tester/get-affected-packages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@ import { parseMajorVersionFromDirectoryName } from "../lib/definition-parser";
import { AllPackages, PackageBase, TypingsData } from "../lib/packages";
import { sourceBranch, typesDirectoryName } from "../lib/settings";
import { Logger } from "../util/logging";
import { done, execAndThrowErrors, flatMap, join, map, mapDefined, sort } from "../util/util";
import { done, execAndThrowErrors, flatMap, map, mapDefined, sort } from "../util/util";

if (!module.parent) {
done(main(Options.defaults));
}
async function main(options: Options): Promise<void> {
const changes = await getAffectedPackages(await AllPackages.read(options), console.log, options);
console.log(join(map(changes, t => t.desc)));
console.log({ changedPackages: changes.changedPackages.map(t => t.desc), dependers: changes.dependentPackages.map(t => t.desc) });
}

export interface Affected {
readonly changedPackages: ReadonlyArray<TypingsData>;
readonly dependentPackages: ReadonlyArray<TypingsData>;
}

/** Gets all packages that have changed on this branch, plus all packages affected by the change. */
export default async function getAffectedPackages(allPackages: AllPackages, log: Logger, options: Options): Promise<TypingsData[]> {
export default async function getAffectedPackages(allPackages: AllPackages, log: Logger, options: Options): Promise<Affected> {
const changedPackageIds = await gitChanges(log, options);
// If a package doesn't exist, that's because it was deleted.
const changedPackages = mapDefined(changedPackageIds, (({ name, majorVersion }) =>
majorVersion === "latest" ? allPackages.tryGetLatestVersion(name) : allPackages.tryGetTypingsData({ name, majorVersion })));
const dependedOn = getReverseDependencies(allPackages);
return collectDependers(changedPackages, dependedOn);
const dependentPackages = collectDependers(changedPackages, getReverseDependencies(allPackages)).filter(d => changedPackages.includes(d));
return { changedPackages, dependentPackages };
}

/** Every package name in the original list, plus their dependencies (incl. dependencies' dependencies). */
export function allDependencies(allPackages: AllPackages, packages: ReadonlyArray<TypingsData>): TypingsData[] {
export function allDependencies(allPackages: AllPackages, packages: Iterable<TypingsData>): TypingsData[] {
return sortPackages(transitiveClosure(packages, pkg => allPackages.allDependencyTypings(pkg)));
}

Expand Down
44 changes: 26 additions & 18 deletions src/tester/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Options } from "../lib/common";
import { AllPackages, PackageBase, TypingsData } from "../lib/packages";
import { npmInstallFlags } from "../util/io";
import { LoggerWithErrors, moveLogsWithErrors, quietLoggerWithErrors } from "../util/logging";
import { done, exec, execAndThrowErrors, joinPaths, nAtATime, numberOfOsProcesses } from "../util/util";
import { concat, done, exec, execAndThrowErrors, joinPaths, nAtATime, numberOfOsProcesses } from "../util/util";

import getAffectedPackages, { allDependencies } from "./get-affected-packages";
import getAffectedPackages, { Affected, allDependencies } from "./get-affected-packages";

if (!module.parent) {
const selection = yargs.argv.all ? "all" : yargs.argv._[0] ? new RegExp(yargs.argv._[0]) : "affected";
Expand Down Expand Up @@ -38,21 +38,22 @@ export function testerOptions(runFromDefinitelyTyped: boolean): Options {

export default async function main(options: Options, nProcesses: number, selection: "all" | "affected" | RegExp): Promise<void> {
const allPackages = await AllPackages.read(options);
const typings = selection === "all"
? allPackages.allTypings()
const { changedPackages, dependentPackages }: Affected = selection === "all"
? { changedPackages: allPackages.allTypings(), dependentPackages: [] }
: selection === "affected"
? await getAffectedPackages(allPackages, console.log, options)
: allPackages.allTypings().filter(t => selection.test(t.name));
: { changedPackages: allPackages.allTypings().filter(t => selection.test(t.name)), dependentPackages: [] };

console.log(`Testing ${typings.length} packages: ${typings.map(t => t.desc)}`);
console.log(`Testing ${changedPackages.length} changed packages: ${changedPackages.map(t => t.desc)}`);
console.log(`Testing ${dependentPackages.length} dependent packages: ${dependentPackages.map(t => t.desc)}`);
console.log(`Running with ${nProcesses} processes.`);

const allErrors: Array<{ pkg: TypingsData, err: TesterError }> = [];

console.log("Installing NPM dependencies...");

// We need to run `npm install` for all dependencies, too, so that we have dependencies' dependencies installed.
await nAtATime(nProcesses, allDependencies(allPackages, typings), async pkg => {
await nAtATime(nProcesses, allDependencies(allPackages, concat(changedPackages, dependentPackages)), async pkg => {
const cwd = pkg.directoryPath(options);
if (!await pathExists(joinPaths(cwd, "package.json"))) {
return;
Expand All @@ -69,19 +70,12 @@ export default async function main(options: Options, nProcesses: number, selecti
}
});

await runCommand(console, undefined, pathToDtsLint, "--installAll");
await runCommand(console, undefined, pathToDtsLint, ["--installAll"]);

console.log("Testing...");

await nAtATime(nProcesses, typings, async pkg => {
const [log, logResult] = quietLoggerWithErrors();
const err = await runCommand(log, pkg.directoryPath(options), pathToDtsLint);
console.log(`Testing ${pkg.desc}`);
moveLogsWithErrors(console, logResult(), msg => `\t${msg}`);
if (err) {
allErrors.push({ err, pkg });
}
});
await runTests(changedPackages, false);
await runTests(dependentPackages, true);

if (allErrors.length) {
allErrors.sort(({ pkg: pkgA }, { pkg: pkgB}) => PackageBase.compare(pkgA, pkgB));
Expand All @@ -96,13 +90,27 @@ export default async function main(options: Options, nProcesses: number, selecti

throw new Error("There was a test failure.");
}

async function runTests(packages: ReadonlyArray<TypingsData>, isDepender: boolean): Promise<void> {
await nAtATime(nProcesses, packages, pkg => runTest(pkg, isDepender));
}

async function runTest(pkg: TypingsData, isDepender: boolean): Promise<void> {
const [log, logResult] = quietLoggerWithErrors();
const err = await runCommand(log, pkg.directoryPath(options), pathToDtsLint, isDepender ? ["--onlyTestTsNext"] : []);
console.log(`Testing ${pkg.desc}`);
moveLogsWithErrors(console, logResult(), msg => `\t${msg}`);
if (err) {
allErrors.push({ err, pkg });
}
}
}

interface TesterError {
message: string;
}

async function runCommand(log: LoggerWithErrors, cwd: string | undefined, cmd: string, ...args: string[]): Promise<TesterError | undefined> {
async function runCommand(log: LoggerWithErrors, cwd: string | undefined, cmd: string, args: string[]): Promise<TesterError | undefined> {
const nodeCmd = `node ${cmd} ${args.join(" ")}`;
log.info(`Running: ${nodeCmd}`);
try {
Expand Down
5 changes: 5 additions & 0 deletions src/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ export function multiMapAdd<K, V>(map: Map<K, V[]>, key: K, value: V): void {
}
}

export function* concat<T>(a: Iterable<T>, b: Iterable<T>): Iterable<T> {
yield* a;
yield* b;
}

export function mapDefined<T, U>(arr: Iterable<T>, mapper: (t: T) => U | undefined): U[] {
const out = [];
for (const a of arr) {
Expand Down