Skip to content

Commit

Permalink
feat: nicer resolving of versions
Browse files Browse the repository at this point in the history
  • Loading branch information
acunniffe committed Mar 19, 2022
1 parent 817b03e commit 0376fed
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 48 deletions.
15 changes: 6 additions & 9 deletions src/workflows/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export async function createResourceAction(resourceName, pluralResourceName) {
},
);

const spec = buildNewResourceSpec(titleResourceName);
const spec = buildNewResourceSpec(
titleResourceName,
resourceName,
pluralResourceName,
);
const specYaml = writeYaml(spec);
fs.writeFileSync(
path.join(resourcesDirectory, lowerCaseResourceName, version, "spec.yaml"),
Expand All @@ -49,12 +53,7 @@ export const addUpdateOperationAction =

function buildOperationAction(template) {
// TODO: consider how workflows can provided with more sophisticated context
return async (
resourceName: string,
pluralResourceName: string,
resourceVersion: string,
) => {
const titleResourceName = titleCase(resourceName);
return async (pluralResourceName: string, resourceVersion: string) => {
const specFilePath = await resolveResourceVersion(
process.cwd(),
pluralResourceName,
Expand All @@ -64,8 +63,6 @@ function buildOperationAction(template) {
// and whether that's something we need to address here
await applyTemplate(template, specFilePath, {
pluralResourceName,
resourceName,
titleResourceName,
});
};
}
Expand Down
5 changes: 2 additions & 3 deletions src/workflows/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ export const addUpdateOperationCommand = buildOperationCommand(

function buildOperationCommand(name: string, description: string, action) {
const command = new Command(name)
.addArgument(new Argument("<resource-name>", "[resource-name]"))
.addArgument(
new Argument("<plural-resource-name>", "[plural-resource-name]"),
)
.addArgument(new Argument("[resource-version]", "version"))
.action(async (resourceName, pluralResourceName, resourceVersion) => {
return action(resourceName, pluralResourceName, resourceVersion);
.action(async (pluralResourceName, resourceVersion) => {
return action(pluralResourceName, resourceVersion);
});

command.description(description);
Expand Down
21 changes: 17 additions & 4 deletions src/workflows/file-resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import findParentDir from "find-parent-dir";
import fs from "fs-extra";
import path from "path";
import { OpenAPIV3 } from "@useoptic/openapi-utilities";

export async function resolveResourcesDirectory(
workingDirectory: string = process.cwd(),
Expand Down Expand Up @@ -51,10 +52,6 @@ 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(),
Expand All @@ -64,3 +61,19 @@ export function formatResourceVersion(date: Date = new Date()): string {
function padWithZero(value: number): string {
return ("00" + value).slice(-2);
}

export function getSingularAndPluralName(openApi: OpenAPIV3.Document) {
const singular = openApi.info["x-singular-name"];
const plural = openApi.info["x-plural-name"];

if (!singular || !plural)
throw new Error(
"info.x-singular-name and info.x-plural-name must be set to use our OpenAPI workflow generators ",
);

return { singular, plural };
}

export function titleCase(value: string): string {
return value[0].toUpperCase() + value.slice(1);
}
17 changes: 15 additions & 2 deletions src/workflows/templates/new-resource-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import { refs } from "./common";

export function buildNewResourceSpec(
titleResourceName: string,
name: string,
pluralName: string,
): OpenAPIV3.Document {
const spec: OpenAPIV3.Document = baseOpenApiSpec(titleResourceName);
const spec: OpenAPIV3.Document = baseOpenApiSpec(
titleResourceName,
name,
pluralName,
);
if (!spec.components) spec.components = {};
if (!spec.components.schemas) spec.components.schemas = {};
spec.components.schemas[`${titleResourceName}Attributes`] = {
Expand All @@ -18,12 +24,19 @@ export function buildNewResourceSpec(
return spec;
}

function baseOpenApiSpec(titleResourceName: string): OpenAPIV3.Document {
function baseOpenApiSpec(
titleResourceName: string,
name: string,
pluralName: string,
): OpenAPIV3.Document {
return {
openapi: "3.0.3",
info: {
title: `${titleResourceName} Resource`,
version: "3.0.0",
// @ts-ignore
"x-plural-name": pluralName,
"x-singular-name": name,
},
servers: [
{ url: "https://api.snyk.io/v3", description: "Public Snyk API" },
Expand Down
11 changes: 6 additions & 5 deletions src/workflows/templates/operations/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ensureOrgIdComponent,
} from "../parameters";
import { buildCollectionPath } from "../paths";
import { getSingularAndPluralName, titleCase } from "../../file-resolvers";

export const addCreateOperation = SpecTemplate.create(
"add-create-operation",
Expand All @@ -25,27 +26,27 @@ export const addCreateOperation = SpecTemplate.create(
export function addCreateOperationTemplate(
spec: OpenAPIV3.Document,
options: {
resourceName: string;
titleResourceName: string;
pluralResourceName: string;
},
): void {
const { resourceName, titleResourceName, pluralResourceName } = options;
const { pluralResourceName } = options;
const { singular, plural } = getSingularAndPluralName(spec);
const titleResourceName = titleCase(singular);
const collectionPath = buildCollectionPath(pluralResourceName);
if (!spec.paths) spec.paths = {};
if (!spec.paths[collectionPath]) spec.paths[collectionPath] = {};
if (!spec.components) spec.components = {};
if (!spec.components.schemas) spec.components.schemas = {};
spec.paths[collectionPath]!.post = buildCreateOperation(
resourceName,
singular,
titleResourceName,
);
const attributes =
spec.components?.schemas?.[`${titleResourceName}Attributes`];
if (!attributes)
throw new Error(`Could not find ${titleResourceName}Attributes schema`);
spec.components.schemas[`${titleResourceName}CreateAttributes`] = attributes;
ensureIdParameterComponent(spec, resourceName, titleResourceName);
ensureIdParameterComponent(spec, singular, titleResourceName);
ensureRelationSchemaComponent(spec, titleResourceName);
ensureOrgIdComponent(spec);
}
Expand Down
13 changes: 7 additions & 6 deletions src/workflows/templates/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { OpenAPIV3 } from "openapi-types";
import { SpecTemplate } from "@useoptic/openapi-cli";
import { ensureRelationSchemaComponent } from "../schemas";
import { buildItemPath } from "../paths";
import { getSingularAndPluralName, titleCase } from "../../file-resolvers";

export const addDeleteOperation = SpecTemplate.create(
"add-delete-operation",
Expand All @@ -16,20 +17,20 @@ export const addDeleteOperation = SpecTemplate.create(
export function addDeleteOperationTemplate(
spec: OpenAPIV3.Document,
options: {
resourceName: string;
titleResourceName: string;
pluralResourceName: string;
},
): void {
const { resourceName, titleResourceName, pluralResourceName } = options;
const itemPath = buildItemPath(resourceName, pluralResourceName);
const { pluralResourceName } = options;
const { singular, plural } = getSingularAndPluralName(spec);
const titleResourceName = titleCase(singular);
const itemPath = buildItemPath(singular, pluralResourceName);
if (!spec.paths) spec.paths = {};
if (!spec.paths[itemPath]) spec.paths[itemPath] = {};
spec.paths[itemPath]!.delete = buildDeleteOperation(
resourceName,
singular,
titleResourceName,
);
ensureIdParameterComponent(spec, resourceName, titleResourceName);
ensureIdParameterComponent(spec, singular, titleResourceName);
ensureRelationSchemaComponent(spec, titleResourceName);
ensureOrgIdComponent(spec);
}
Expand Down
16 changes: 7 additions & 9 deletions src/workflows/templates/operations/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { OpenAPIV3 } from "openapi-types";
import { SpecTemplate } from "@useoptic/openapi-cli";
import { buildItemPath } from "../paths";
import { getSingularAndPluralName, titleCase } from "../../file-resolvers";

export const addGetOperation = SpecTemplate.create(
"add-get-operation",
Expand All @@ -24,20 +25,17 @@ export const addGetOperation = SpecTemplate.create(
export function addGetOperationTemplate(
spec: OpenAPIV3.Document,
options: {
resourceName: string;
titleResourceName: string;
pluralResourceName: string;
},
): void {
const { resourceName, titleResourceName, pluralResourceName } = options;
const itemPath = buildItemPath(resourceName, pluralResourceName);
const { pluralResourceName } = options;
const { singular, plural } = getSingularAndPluralName(spec);
const titleResourceName = titleCase(singular);
const itemPath = buildItemPath(singular, pluralResourceName);
if (!spec.paths) spec.paths = {};
if (!spec.paths[itemPath]) spec.paths[itemPath] = {};
spec.paths[itemPath]!.get = buildGetOperation(
resourceName,
titleResourceName,
);
ensureIdParameterComponent(spec, resourceName, titleResourceName);
spec.paths[itemPath]!.get = buildGetOperation(singular, titleResourceName);
ensureIdParameterComponent(spec, singular, titleResourceName);
ensureRelationSchemaComponent(spec, titleResourceName);
ensureOrgIdComponent(spec);
}
Expand Down
9 changes: 5 additions & 4 deletions src/workflows/templates/operations/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { SpecTemplate } from "@useoptic/openapi-cli";
import { ensureOrgIdComponent } from "../parameters";
import { buildCollectionPath } from "../paths";
import { getSingularAndPluralName, titleCase } from "../../file-resolvers";

export const addListOperation = SpecTemplate.create(
"add-list-operation",
Expand All @@ -22,17 +23,17 @@ export const addListOperation = SpecTemplate.create(
export function addListOperationTemplate(
spec: OpenAPIV3.Document,
options: {
resourceName: string;
titleResourceName: string;
pluralResourceName: string;
},
): void {
const { resourceName, titleResourceName, pluralResourceName } = options;
const { pluralResourceName } = options;
const { singular, plural } = getSingularAndPluralName(spec);
const titleResourceName = titleCase(singular);
const collectionPath = buildCollectionPath(pluralResourceName);
if (!spec.paths) spec.paths = {};
if (!spec.paths[collectionPath]) spec.paths[collectionPath] = {};
spec.paths[collectionPath]!.get = buildListOperation(
resourceName,
singular,
titleResourceName,
);
ensureRelationSchemaComponent(spec, titleResourceName);
Expand Down
13 changes: 7 additions & 6 deletions src/workflows/templates/operations/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { OpenAPIV3 } from "openapi-types";
import { SpecTemplate } from "@useoptic/openapi-cli";
import { buildItemPath } from "../paths";
import { getSingularAndPluralName, titleCase } from "../../file-resolvers";

export const addUpdateOperation = SpecTemplate.create(
"add-update-operation",
Expand All @@ -25,27 +26,27 @@ export const addUpdateOperation = SpecTemplate.create(
export function addUpdateOperationTemplate(
spec: OpenAPIV3.Document,
options: {
resourceName: string;
titleResourceName: string;
pluralResourceName: string;
},
): void {
const { resourceName, titleResourceName, pluralResourceName } = options;
const itemPath = buildItemPath(resourceName, pluralResourceName);
const { pluralResourceName } = options;
const { singular, plural } = getSingularAndPluralName(spec);
const titleResourceName = titleCase(singular);
const itemPath = buildItemPath(singular, pluralResourceName);
if (!spec.paths) spec.paths = {};
if (!spec.paths[itemPath]) spec.paths[itemPath] = {};
if (!spec.components) spec.components = {};
if (!spec.components.schemas) spec.components.schemas = {};
spec.paths[itemPath]!.patch = buildUpdateOperation(
resourceName,
singular,
titleResourceName,
);
const attributes =
spec.components?.schemas?.[`${titleResourceName}Attributes`];
if (!attributes)
throw new Error(`Could not find ${titleResourceName}Attributes schema`);
spec.components.schemas[`${titleResourceName}UpdateAttributes`] = attributes;
ensureIdParameterComponent(spec, resourceName, titleResourceName);
ensureIdParameterComponent(spec, singular, titleResourceName);
ensureRelationSchemaComponent(spec, titleResourceName);
ensureOrgIdComponent(spec);
}
Expand Down

0 comments on commit 0376fed

Please sign in to comment.