Skip to content

Commit

Permalink
feat: Add check-package-json CLI command
Browse files Browse the repository at this point in the history
When using `@guardian/cdk` the version of `aws-cdk` libraries in your `package.json` must exactly match the version `@guardian/cdk` uses.

This command allows you to provide a `package.json` file to check if the versions of `aws-cdk` libraries match what `@guardian/cdk` uses.
  • Loading branch information
akash1810 committed Jul 26, 2021
1 parent 0dc667b commit 1095cd1
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
jest.mock("./src/constants/tracking-tag");
jest.mock("./src/constants/library-info");
72 changes: 72 additions & 0 deletions src/bin/commands/check-package-json.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { promises } from "fs";
import { checkPackageJson } from "./check-package-json";

describe("checkPackageJson", () => {
const mockPackageJson = (content: unknown) => {
jest.spyOn(promises, "access").mockReturnValue(Promise.resolve());
jest.spyOn(promises, "readFile").mockReturnValue(Promise.resolve(JSON.stringify(content)));
};

afterEach(() => {
jest.resetAllMocks();
});

it("should succeed when the versions match exactly", async () => {
mockPackageJson({
dependencies: {
"aws-cdk": "0.0.1",
"@aws-cdk/aws-ec2": "0.0.1",
},
});

const actual = await checkPackageJson("/tmp");

const expected = {
file: "/tmp/package.json",
incorrectDependencies: {},
incorrectDevDependencies: {},
versionExpected: "0.0.1",
};

expect(actual).toStrictEqual(expected);
});

it("should fail when the versions do not match exactly", async () => {
mockPackageJson({
dependencies: {
"aws-cdk": "^0.0.1",
"@aws-cdk/aws-ec2": "0.0.1",
},
devDependencies: {
"@aws-cdk/aws-iam": "0.0.2",
},
});

try {
await checkPackageJson("/tmp");
} catch (actual) {
const expected = {
file: "/tmp/package.json",
incorrectDependencies: {
"aws-cdk": "^0.0.1",
},
incorrectDevDependencies: {
"@aws-cdk/aws-iam": "0.0.2",
},
versionExpected: "0.0.1",
};
expect(actual).toStrictEqual(expected);
}
});

it("should fail when the package.json file does not exist", async () => {
jest.spyOn(promises, "access").mockReturnValue(Promise.reject());

try {
await checkPackageJson("/tmp");
} catch (actual) {
const expected = "File not found: /tmp/package.json";
expect(actual).toBe(expected);
}
});
});
39 changes: 39 additions & 0 deletions src/bin/commands/check-package-json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { access, readFile } from "fs/promises";
import path from "path";
import type { PackageJson } from "read-pkg-up";
import { LibraryInfo } from "../../constants/library-info";
import type { CliCommandResponse } from "../../types/command";
import { getAwsCdkDependencies } from "../../utils/package-json";

const filterVersionMismatch = (deps: Record<string, string>) =>
Object.fromEntries(Object.entries(deps).filter(([, version]) => version !== LibraryInfo.AWS_CDK_VERSION));

export const checkPackageJson = async (directory: string): CliCommandResponse => {
const packageJsonPath = path.join(directory, "package.json");

try {
await access(packageJsonPath);
} catch (error) {
return Promise.reject(`File not found: ${packageJsonPath}`);
}

const fileContent = await readFile(packageJsonPath, { encoding: "utf8" });
const packageJson = JSON.parse(fileContent) as PackageJson;

const { dependencies, devDependencies } = getAwsCdkDependencies(packageJson);

const depsMismatch = filterVersionMismatch(dependencies);
const devDepsMismatch = filterVersionMismatch(devDependencies);
const totalMismatch = Object.keys(depsMismatch).length + Object.keys(devDepsMismatch).length;

const isOk = totalMismatch === 0;

const response = {
file: packageJsonPath,
versionExpected: LibraryInfo.AWS_CDK_VERSION,
incorrectDependencies: depsMismatch,
incorrectDevDependencies: devDepsMismatch,
};

return isOk ? Promise.resolve(response) : Promise.reject(response);
};
14 changes: 14 additions & 0 deletions src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import type { CliCommandResponse } from "../types/command";
import { awsCredentialProviderChain } from "./aws-credential-provider";
import { accountReadinessCommand } from "./commands/account-readiness";
import { awsCdkVersionCommand } from "./commands/aws-cdk-version";
import { checkPackageJson } from "./commands/check-package-json";

const Commands = {
AwsCdkVersion: "aws-cdk-version",
AccountReadiness: "account-readiness",
CheckPackageJson: "check-package-json",
};

const parseCommandLineArguments = () => {
Expand All @@ -26,6 +28,14 @@ const parseCommandLineArguments = () => {
.option("region", { type: "string", description: "AWS region", default: "eu-west-1" })
.command(Commands.AwsCdkVersion, "Print the version of @aws-cdk libraries being used")
.command(Commands.AccountReadiness, "Perform checks on an AWS account to see if it is GuCDK ready")
.command(Commands.CheckPackageJson, "Check a package.json file for compatibility with GuCDK", (yargs) =>
yargs.option("directory", {
type: "string",
description: "The location of the package.json file to check",
default: process.cwd(),
defaultDescription: "The current working directory",
})
)
.version(`${LibraryInfo.VERSION} (using @aws-cdk ${LibraryInfo.AWS_CDK_VERSION})`)
.demandCommand(1, "") // just print help
.help()
Expand All @@ -42,6 +52,10 @@ parseCommandLineArguments()
return awsCdkVersionCommand();
case Commands.AccountReadiness:
return accountReadinessCommand({ credentialProvider: awsCredentialProviderChain(profile), region });
case Commands.CheckPackageJson: {
const { directory } = argv;
return checkPackageJson(directory);
}
default:
throw new Error(`Unknown command: ${command}`);
}
Expand Down
10 changes: 10 additions & 0 deletions src/constants/__mocks__/library-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const mockAwsCdkVersion = "0.0.1";

export const LibraryInfo = {
VERSION: "1.0.0",
AWS_CDK_VERSION: mockAwsCdkVersion,
AWS_CDK_VERSIONS: {
"aws-cdk": mockAwsCdkVersion,
"@aws-cdk/core": mockAwsCdkVersion,
},
};

0 comments on commit 1095cd1

Please sign in to comment.