From 817b03eff2803bdbe5ad62a047e845f9759ef8c3 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Fri, 18 Mar 2022 22:00:57 -0400 Subject: [PATCH] no more need for file resolving --- package.json | 1 + src/workflows/actions.ts | 46 ++++++++++++----------- src/workflows/commands.ts | 6 +-- src/workflows/file-resolvers.ts | 66 +++++++++++++++++++++++++++++++++ yarn.lock | 5 +++ 5 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 src/workflows/file-resolvers.ts diff --git a/package.json b/package.json index eb2d021e..543a843f 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@useoptic/openapi-utilities": "0.23.4", "chai": "^4.3.4", "change-case": "^4.1.2", + "find-parent-dir": "^0.3.1", "fs-extra": "^10.0.0", "lodash.isequal": "^4.5.0", "nice-try": "^3.0.0", diff --git a/src/workflows/actions.ts b/src/workflows/actions.ts index 397c895e..8b3162cc 100644 --- a/src/workflows/actions.ts +++ b/src/workflows/actions.ts @@ -8,24 +8,32 @@ import { addGetOperation } from "./templates/operations/get"; import { addUpdateOperation } from "./templates/operations/update"; import { addDeleteOperation } from "./templates/operations/delete"; import { buildNewResourceSpec } from "./templates/new-resource-spec"; +import { + formatResourceVersion, + resolveResourcesDirectory, + resolveResourceVersion, +} from "./file-resolvers"; export async function createResourceAction(resourceName, pluralResourceName) { // TODO: the SDK should probably help with the generation of new files // and allow ergonomic use of a SpecTemplate to do so const titleResourceName = titleCase(resourceName); - const version = getResourceVersion(); - const collectionPath = `/${pluralResourceName}`; - if (!fs.existsSync(path.join(".", "resources"))) - throw new Error( - "Resource directory does not exist. Are you sure you're in the right directory?", - ); - await fs.mkdirSync(path.join(".", "resources", pluralResourceName, version), { - recursive: true, - }); + const version = formatResourceVersion(); + + const resourcesDirectory = await resolveResourcesDirectory(); + const lowerCaseResourceName = pluralResourceName.toLowerCase(); + + await fs.mkdirSync( + path.join(resourcesDirectory, lowerCaseResourceName, version), + { + recursive: true, + }, + ); + const spec = buildNewResourceSpec(titleResourceName); const specYaml = writeYaml(spec); fs.writeFileSync( - path.join(".", "resources", pluralResourceName, version, "spec.yaml"), + path.join(resourcesDirectory, lowerCaseResourceName, version, "spec.yaml"), specYaml, ); } @@ -42,11 +50,16 @@ export const addUpdateOperationAction = function buildOperationAction(template) { // TODO: consider how workflows can provided with more sophisticated context return async ( - specFilePath: string, resourceName: string, pluralResourceName: string, + resourceVersion: string, ) => { const titleResourceName = titleCase(resourceName); + const specFilePath = await resolveResourceVersion( + process.cwd(), + pluralResourceName, + resourceVersion, + ); // TODO: consider how this impacts performance (round trip to the FS for each call) // and whether that's something we need to address here await applyTemplate(template, specFilePath, { @@ -59,17 +72,6 @@ function buildOperationAction(template) { //----- -function getResourceVersion(): string { - const today = new Date(); - return `${today.getFullYear()}-${padWithZero(today.getMonth())}-${padWithZero( - today.getUTCDay(), - )}`; -} - -function padWithZero(value: number): string { - return ("00" + value).slice(-2); -} - function titleCase(value: string): string { return value[0].toUpperCase() + value.slice(1); } diff --git a/src/workflows/commands.ts b/src/workflows/commands.ts index 9fa52991..7f25f6de 100644 --- a/src/workflows/commands.ts +++ b/src/workflows/commands.ts @@ -55,13 +55,13 @@ export const addUpdateOperationCommand = buildOperationCommand( function buildOperationCommand(name: string, description: string, action) { const command = new Command(name) - .addArgument(new Argument("", "path to openapi file")) .addArgument(new Argument("", "[resource-name]")) .addArgument( new Argument("", "[plural-resource-name]"), ) - .action(async (specFilePath, resourceName, pluralResourceName) => { - return action(specFilePath, resourceName, pluralResourceName); + .addArgument(new Argument("[resource-version]", "version")) + .action(async (resourceName, pluralResourceName, resourceVersion) => { + return action(resourceName, pluralResourceName, resourceVersion); }); command.description(description); diff --git a/src/workflows/file-resolvers.ts b/src/workflows/file-resolvers.ts new file mode 100644 index 00000000..34c3c5f1 --- /dev/null +++ b/src/workflows/file-resolvers.ts @@ -0,0 +1,66 @@ +import findParentDir from "find-parent-dir"; +import fs from "fs-extra"; +import path from "path"; + +export async function resolveResourcesDirectory( + workingDirectory: string = process.cwd(), +): Promise { + return new Promise((resolve) => { + findParentDir(workingDirectory, "resources", function (err, dir) { + if (err) + throw new Error( + "A Vervet resources directory does not exist here. Is your working directory correct?", + ); + resolve(path.join(dir, "resources")); + }); + }); +} + +export async function resolveResourceVersion( + workingDirectory: string = process.cwd(), + resourceName: string, + resourceVersion: string = "latest", +): Promise { + const resources = await resolveResourcesDirectory(); + const resourceNameLowerCase = resourceName.toLowerCase(); + + const resourceNames = await fs.readdir(resources); + + if (!resourceNames.includes(resourceNameLowerCase)) + throw new Error( + `No resource ${resourceNameLowerCase} found in directory ${resources}`, + ); + + const resourceDir = path.join(resources, resourceNameLowerCase); + const versions = await fs.readdir(resourceDir); + + const matchingDate = + resourceVersion !== "latest" + ? versions.find((date) => date === resourceVersion) + : latestDateOfSet(versions); + + if (!matchingDate) + throw new Error( + `No resource version ${resourceVersion} found for ${resourceNameLowerCase}`, + ); + + return path.join(resources, resourceNameLowerCase, matchingDate, "spec.yaml"); +} + +function latestDateOfSet(dates: string[]): string | undefined { + return dates.sort().pop(); +} + +function isDate(dateStr) { + return !isNaN(new Date(dateStr).getDate()); +} + +export function formatResourceVersion(date: Date = new Date()): string { + return `${date.getFullYear()}-${padWithZero(date.getMonth())}-${padWithZero( + date.getUTCDay(), + )}`; +} + +function padWithZero(value: number): string { + return ("00" + value).slice(-2); +} diff --git a/yarn.lock b/yarn.lock index 17f30536..44f76d98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3514,6 +3514,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-parent-dir@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.1.tgz#c5c385b96858c3351f95d446cab866cbf9f11125" + integrity sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A== + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"