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

fix: ESLint issues in botbuilder-repo-utils #4838

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
10 changes: 0 additions & 10 deletions libraries/botbuilder-repo-utils/eslint.config.cjs

This file was deleted.

3 changes: 1 addition & 2 deletions libraries/botbuilder-repo-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"dayjs": "^1.11.13",
"fast-glob": "^3.3.2",
"lodash": "^4.17.20",
"eslint-plugin-only-warn": "^1.1.0",
"minimatch": "^9.0.5",
"minimist": "^1.2.6",
"p-map": "^4.0.0"
Expand All @@ -27,7 +26,7 @@
"typescript": "~4.7"
},
"scripts": {
"lint": "eslint .",
"lint": "eslint . --config ../../eslint.config.cjs",
"test": "mocha -r ts-node/register tests/*.test.ts",
"update-versions": "ts-node src/updateVersions.ts"
}
Expand Down
2 changes: 0 additions & 2 deletions libraries/botbuilder-repo-utils/src/file.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/* eslint-disable security/detect-non-literal-fs-filename */

import fs from 'fs';
import util from 'util';

Expand Down
194 changes: 98 additions & 96 deletions libraries/botbuilder-repo-utils/src/updateVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface PackageVersionOptions {
export const getPackageVersion = (
pkg: Partial<Package>,
newVersion: string,
options: PackageVersionOptions
options: PackageVersionOptions,
): string => {
const prerelease = [];

Expand All @@ -59,109 +59,111 @@ export const getPackageVersion = (
return compact([newVersion, compact(prerelease).join('.')]).join('-');
};

export const command = (argv: string[], quiet = false) => async (): Promise<Result> => {
// Obtain the path of the repo root, useful for constructing absolute paths
const repoRoot = await gitRoot();

const packageFile = await readJsonFile<Package>(path.join(repoRoot, 'package.json'));
if (!packageFile) {
return failure('package.json not found', 20);
}

// Parse process.argv for all configuration options
const {
_: [maybeNewVersion],
...flags
} = minimist(argv, {
default: {
deprecated: 'deprecated',
git: 'false',
internal: 'internal',
preview: 'preview',
},
string: ['buildLabel', 'date', 'deprecated', 'git', 'internal', 'preview'],
});

// If `maybeNewVersion` is falsy use version from the root packge.json file
const newVersion = maybeNewVersion || packageFile.version;
if (!newVersion) {
return failure('unable to resolve new version', 21);
}

// Fetch and format date, if instructed
const date = flags.date ? dayjs().format(flags.date) : undefined;

// Read git commit sha if instructed (JSON.parse properly coerces strings to boolean)
const commitSha = JSON.parse(flags.git) ? await gitSha('HEAD') : undefined;
export const command =
(argv: string[], quiet = false) =>
async (): Promise<Result> => {
// Obtain the path of the repo root, useful for constructing absolute paths
const repoRoot = await gitRoot();

const packageFile = await readJsonFile<Package>(path.join(repoRoot, 'package.json'));
if (!packageFile) {
return failure('package.json not found', 20);
}

// Parse process.argv for all configuration options
const {
_: [maybeNewVersion],
...flags
} = minimist(argv, {
default: {
deprecated: 'deprecated',
git: 'false',
internal: 'internal',
preview: 'preview',
},
string: ['buildLabel', 'date', 'deprecated', 'git', 'internal', 'preview'],
});

// If `maybeNewVersion` is falsy use version from the root packge.json file
const newVersion = maybeNewVersion || packageFile.version;
if (!newVersion) {
return failure('unable to resolve new version', 21);
}

// Fetch and format date, if instructed
const date = flags.date ? dayjs().format(flags.date) : undefined;

// Read git commit sha if instructed (JSON.parse properly coerces strings to boolean)
const commitSha = JSON.parse(flags.git) ? await gitSha('HEAD') : undefined;

const projects: string[] = [
...(packageFile.workspaces?.packages || []),
...(packageFile.workspaces?.generators || []),
];

// Collect all workspaces from the repo root. Returns workspaces with absolute paths.
const workspaces = await collectWorkspacePackages(repoRoot, projects);

// Build an object mapping a package name to its new, updated version
const workspaceVersions = workspaces.reduce<Record<string, string>>(
(acc, { pkg }) => ({
...acc,
[pkg.name]: getPackageVersion(pkg, pkg.private ? pkg.version : newVersion, {
buildLabel: flags.buildLabel,
commitSha,
date,
deprecated: flags.deprecated,
internal: flags.internal,
preview: flags.preview,
// Collect all workspaces from the repo root. Returns workspaces with absolute paths.
const workspaces = await collectWorkspacePackages(repoRoot, projects);

// Build an object mapping a package name to its new, updated version
const workspaceVersions = workspaces.reduce<Record<string, string>>(
(acc, { pkg }) => ({
...acc,
[pkg.name]: getPackageVersion(pkg, pkg.private ? pkg.version : newVersion, {
buildLabel: flags.buildLabel,
commitSha,
date,
deprecated: flags.deprecated,
internal: flags.internal,
preview: flags.preview,
}),
}),
}),
{}
);

// Rewrites the version for any dependencies found in `workspaceVersions`
const rewriteWithNewVersions = (dependencies: Record<string, string>) =>
Object.entries(dependencies)
.map(([dependency, version]) => [dependency, workspaceVersions[dependency] ?? version])
.reduce<Record<string, string>>((acc, [dependency, version]) => {
acc[dependency] = version;
return acc;
}, {});

// Rewrite package.json files by updating version as well as dependencies, devDependencies and peerDependencies.
const results = await Promise.all<Result>(
workspaces.map(async ({ absPath, pkg }) => {
const newVersion = workspaceVersions[pkg.name];

if (newVersion) {
if (!quiet) {
console.log(`Updating ${pkg.name} to ${newVersion}`);
{},
);

// Rewrites the version for any dependencies found in `workspaceVersions`
const rewriteWithNewVersions = (dependencies: Record<string, string>) =>
Object.entries(dependencies)
.map(([dependency, version]) => [dependency, workspaceVersions[dependency] ?? version])
.reduce<Record<string, string>>((acc, [dependency, version]) => {
acc[dependency] = version;
return acc;
}, {});

// Rewrite package.json files by updating version as well as dependencies, devDependencies and peerDependencies.
const results = await Promise.all<Result>(
workspaces.map(async ({ absPath, pkg }) => {
const newVersion = workspaceVersions[pkg.name];

if (newVersion) {
if (!quiet) {
console.log(`Updating ${pkg.name} to ${newVersion}`);
}
pkg.version = newVersion.toString();
}
pkg.version = newVersion.toString();
}

if (pkg.dependencies) {
pkg.dependencies = rewriteWithNewVersions(pkg.dependencies);
}

if (pkg.devDependencies) {
pkg.devDependencies = rewriteWithNewVersions(pkg.devDependencies);
}

if (pkg.peerDependencies) {
pkg.peerDependencies = rewriteWithNewVersions(pkg.peerDependencies);
}

try {
await writeJsonFile(absPath, pkg);
return success();
} catch (err: any) {
return failure(err instanceof Error ? err.message : err, 22);
}
})
);

return results.find(isFailure) ?? success();
};

if (pkg.dependencies) {
pkg.dependencies = rewriteWithNewVersions(pkg.dependencies);
}

if (pkg.devDependencies) {
pkg.devDependencies = rewriteWithNewVersions(pkg.devDependencies);
}

if (pkg.peerDependencies) {
pkg.peerDependencies = rewriteWithNewVersions(pkg.peerDependencies);
}

try {
await writeJsonFile(absPath, pkg);
return success();
} catch (err: any) {
return failure(err instanceof Error ? err.message : err, 22);
}
}),
);

return results.find(isFailure) ?? success();
};

if (require.main === module) {
run(command(process.argv.slice(2)));
Expand Down
94 changes: 46 additions & 48 deletions libraries/botbuilder-repo-utils/src/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface Filters {
export async function collectWorkspacePackages(
repoRoot: string,
workspaces: string[] = [],
filters: Partial<Filters> = {}
filters: Partial<Filters> = {},
): Promise<Array<Workspace>> {
// Note: posix is required, this emits absolute paths that are platform specific
const paths = await glob(
Expand All @@ -48,54 +48,52 @@ export async function collectWorkspacePackages(
);

const maybeWorkspaces = await Promise.all(
paths.map(
async (absPath): Promise<Workspace | undefined> => {
let relPath = absPath.replace(repoRoot, '');
if (relPath[0] === path.sep) {
relPath = relPath.slice(1);
}

// Strip `package.json` filename for path filters
const relWorkspacePath = path.dirname(relPath);

if (filters.path?.length && !filters.path.some((path) => minimatch(relWorkspacePath, path))) {
return;
}

if (
filters.ignorePath?.length &&
filters.ignorePath.some((ignorePath) => minimatch(relWorkspacePath, ignorePath))
) {
return;
}

const pkg = await readJsonFile<Package>(absPath);
if (!pkg) {
return undefined;
}

if (filters.noPrivate && pkg.private) {
return;
}

if (filters.script && !(pkg.scripts ?? {})[filters.script]) {
return;
}

if (filters.name?.length && !filters.name.some((name) => minimatch(pkg.name, name))) {
return;
}

if (
filters.ignoreName?.length &&
filters.ignoreName.some((ignoreName) => minimatch(pkg.name, ignoreName))
) {
return;
}

return { absPath, pkg, relPath };
paths.map(async (absPath): Promise<Workspace | undefined> => {
let relPath = absPath.replace(repoRoot, '');
if (relPath[0] === path.sep) {
relPath = relPath.slice(1);
}
)

// Strip `package.json` filename for path filters
const relWorkspacePath = path.dirname(relPath);

if (filters.path?.length && !filters.path.some((path) => minimatch(relWorkspacePath, path))) {
return;
}

if (
filters.ignorePath?.length &&
filters.ignorePath.some((ignorePath) => minimatch(relWorkspacePath, ignorePath))
) {
return;
}

const pkg = await readJsonFile<Package>(absPath);
if (!pkg) {
return undefined;
}

if (filters.noPrivate && pkg.private) {
return;
}

if (filters.script && !(pkg.scripts ?? {})[filters.script]) {
return;
}

if (filters.name?.length && !filters.name.some((name) => minimatch(pkg.name, name))) {
return;
}

if (
filters.ignoreName?.length &&
filters.ignoreName.some((ignoreName) => minimatch(pkg.name, ignoreName))
) {
return;
}

return { absPath, pkg, relPath };
}),
);

return compact(maybeWorkspaces);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import assert from 'assert';
import dayjs from 'dayjs';
import path from 'path';
import semver from 'semver';
import sinon from 'sinon';
import { createSandbox, match } from 'sinon';
import { Package } from '../src/package';
import { command, getPackageVersion } from '../src/updateVersions';
import { isSuccess } from '../src/run';
Expand Down Expand Up @@ -147,8 +147,9 @@ describe('updateVersions', function () {

describe('command', function () {
let sandbox: sinon.SinonSandbox;

beforeEach(function () {
sandbox = sinon.createSandbox();
sandbox = createSandbox();
});

afterEach(function () {
Expand Down Expand Up @@ -223,10 +224,10 @@ describe('updateVersions', function () {
),
});

let packageMatch = sinon.match.hasOwn('version', workspace.expectedVersion);
let packageMatch = match.hasOwn('version', workspace.expectedVersion);
if (workspace.expectedDependencies) {
packageMatch = packageMatch.and(
sinon.match.hasOwn('dependencies', sinon.match(workspace.expectedDependencies)),
match.hasOwn('dependencies', match(workspace.expectedDependencies)),
);
}

Expand Down
Loading