Skip to content

Commit

Permalink
Add finding missing SDKs and generate TS readme commands #2 (#30)
Browse files Browse the repository at this point in the history
* Add finding missing SDKs command

* Remove getCommandLineParameterValue function

* Add draft of generating TS readme

* Promisify gulp tasks

* Skip non directories

* Add Logger

* Add generating new TypeScript readme

* Fix typo

* Fix package.json

* Address code review comments
  • Loading branch information
kpajdzik authored Oct 4, 2018
1 parent 28d7e68 commit 04bd3f4
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 33 deletions.
128 changes: 105 additions & 23 deletions .scripts/generate-sdks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,33 @@
* license information.
*/

import * as colors from "colors";
import * as fssync from "fs";
import { promises as fs } from "fs";
import * as path from "path";
import * as minimist from "minimist";
import * as yaml from "js-yaml";
import { CommandLineOptions, SdkType } from "./commandLineOptions";
import { Logger } from "./logger";

interface readmeSettings {
"nodejs": {
"azure-arm": boolean;
"license-header": string;
"payload-flattening-threshold": number;
"package-name": string;
"output-folder": string;
"generate-license-txt": boolean | undefined;
"generate-package-json": boolean | undefined;
"generate-readme-md": boolean | undefined;
"generate-metadata": boolean | undefined;
} | undefined;
}

const repositoryName = "azure-rest-api-specs";
const specificationsSegment = "specification";

const args = minimist(process.argv.slice(2), {
string: [ "package", "type" ],
string: ["package", "type"],
boolean: ["debug", "verbose"],
alias: {
d: "debug",
Expand All @@ -28,7 +42,11 @@ const args = minimist(process.argv.slice(2), {
}
}) as CommandLineOptions;

const logger = new Logger(args);
const _logger = new Logger(args);

if (!fs) {
throw new Error("This script has to be run on Node.js 10.0+");
}

function contains<T>(array: T[], el: T): boolean {
return array.indexOf(el) != -1
Expand All @@ -47,17 +65,17 @@ async function exists(path: string): Promise<boolean> {
});
}

args.getSdkType = function() {
const resourceManagerStrings = [ "arm", "rm", "resourcemanager" ]
const dataPlaneStrings = [ "dp", "data", "dataplane" ]
args.getSdkType = function () {
const resourceManagerStrings = ["arm", "rm", "resourcemanager"]
const dataPlaneStrings = ["dp", "data", "dataplane"]

const type = this.type.toLowerCase().replace("-", "");
if (contains(resourceManagerStrings, type)) {
return SdkType.ResourceManager;
} else if (contains(dataPlaneStrings, type)) {
return SdkType.DataPlane;
} else {
throw new Error("Uknown SDK type");
throw new Error("Unknown SDK type");
}
}

Expand Down Expand Up @@ -101,7 +119,7 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom

for (const serviceDirectory of serviceSpecs) {
const fullServicePath = path.resolve(specsDirectory, serviceDirectory);
if (!(await !isDirectory(fullServicePath))) {
if (!(await isDirectory(fullServicePath))) {
continue;
}

Expand All @@ -122,16 +140,17 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom
} else if (readmeFiles.length == 1) {
const readmeMdPath = readmeFiles[0];
if (await doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath)) {
console.log(colors.red(fullSpecName))
} else {
console.log(colors.green(fullSpecName))
missingSdks.push(fullSdkPath);
_logger.logRed(`${fullSpecName}`);
} else if (args.debug) {
_logger.logGreen(fullSpecName);
}
} else if (contains(readmeFiles, "readme.nodejs.md")) {
if (!contains(readmeFiles, "readme.typescript.md")) {
missingSdks.push(fullSdkPath);
console.log(colors.red(fullSpecName))
_logger.logRed(`${fullSpecName}`);
} else if (args.debug) {
console.log(colors.green(fullSpecName))
_logger.logGreen(fullSpecName);
}
}
}
Expand All @@ -140,35 +159,98 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom
return missingSdks;
}

async function doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath: string): Promise<boolean> {
const readmeMdBuffer = await fs.readFile(readmeMdPath);
const sectionBeginning = "``` yaml $(swagger-to-sdk)"
const sectionEnd = "```"

const beginningIndex = readmeMdBuffer.indexOf(sectionBeginning);
const trimmedBuffer = readmeMdBuffer.slice(beginningIndex);
async function getYamlSection(buffer: Buffer, sectionBeginning: string, sectionEnd: string): Promise<Buffer> {
const beginningIndex = buffer.indexOf(sectionBeginning);
const trimmedBuffer = buffer.slice(beginningIndex + (sectionBeginning.length));

const endIndex = trimmedBuffer.indexOf(sectionEnd);
const endIndex = trimmedBuffer.indexOf(sectionEnd, 3);
const sectionBuffer = trimmedBuffer.slice(0, endIndex);

return sectionBuffer;
}

async function doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath: string): Promise<boolean> {
const readmeMdBuffer = await fs.readFile(readmeMdPath);
const sectionBuffer = await getYamlSection(readmeMdBuffer, "``` yaml $(swagger-to-sdk)", "```");

if (sectionBuffer.includes("azure-sdk-for-js")) {
return true;
}

return false;
}

export async function copyExistingNodeJsReadme(sdkPath: string): Promise<void> {
export async function copyExistingNodeJsReadme(sdkPath: string): Promise<string> {
const nodeJsReadmePath = path.resolve(sdkPath, "readme.nodejs.md");
const typescriptReadmePath = path.resolve(sdkPath, "readme.typescript.md");

if (args.verbose) {
console.log(`Copying ${nodeJsReadmePath} to ${typescriptReadmePath}`)
_logger.log(`Copying ${nodeJsReadmePath} to ${typescriptReadmePath}`)
}

if (await exists(typescriptReadmePath)) {
throw new Error(`${typescriptReadmePath} file already exists`)
}

await fs.copyFile(nodeJsReadmePath, typescriptReadmePath);
return typescriptReadmePath;
}

async function updatePackageName(settings: readmeSettings): Promise<readmeSettings> {
const packageName = settings.nodejs["package-name"]
if (packageName.startsWith("arm") || !packageName.startsWith("azure-")) {
return settings;
}

settings.nodejs["package-name"] = packageName.replace("azure-", "");
return settings;
}

async function updateMetadataFields(settings: readmeSettings): Promise<readmeSettings> {
settings.nodejs["generate-metadata"] = true;
delete settings.nodejs["generate-license-txt"]
delete settings.nodejs["generate-package-json"]
delete settings.nodejs["generate-readme-md"];

return settings;
}

async function updateOutputFolder(settings: readmeSettings): Promise<readmeSettings> {
settings.nodejs["output-folder"] = `$(typescript-sdks-folder)/packages/${settings.nodejs["package-name"]}`;
return settings;
}

async function updateYamlSection(sectionText: string): Promise<string> {
const section = yaml.safeLoad(sectionText);
await updatePackageName(section);
await updateMetadataFields(section);
await updateOutputFolder(section);
section["typescript"] = section.nodejs;
delete section.nodejs;

return yaml.safeDump(section).trim();
}

export async function updateTypeScriptReadmeFile(typescriptReadmePath: string): Promise<string> {
const readmeBuffer: Buffer = await fs.readFile(typescriptReadmePath);
const readme: string = readmeBuffer.toString();
let outputReadme = readme;

const yamlSection = await getYamlSection(readmeBuffer, "``` yaml $(nodejs)", "```");
const sectionText = yamlSection.toString().trim();
const updatedYamlSection = await updateYamlSection(sectionText);

outputReadme = outputReadme.replace(sectionText, updatedYamlSection);
outputReadme = outputReadme.replace("azure-sdk-for-node", "azure-sdk-for-js");
outputReadme = outputReadme.replace("Node.js", "TypeScript");
outputReadme = outputReadme.replace("$(nodejs)", "$(typescript)");
outputReadme = outputReadme.replace("nodejs", "typescript");
outputReadme = outputReadme.replace("Node", "TypeScript");
outputReadme = outputReadme.replace("node", "typescript");

return outputReadme;
}

export async function saveContentToFile(filePath: string, content: string): Promise<void> {
await fs.writeFile(filePath, content);
}
36 changes: 30 additions & 6 deletions .scripts/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,49 @@
* license information.
*/

import * as colors from "colors";
import { CommandLineOptions } from "./commandLineOptions";

export enum Color {
Red,
Green
}

export class Logger {
private _colorsMap = {
[Color.Red]: colors.red,
[Color.Green]: colors.green
}

constructor(private _options: CommandLineOptions) {
}

log(text: string): void {
console.log(text);
log(text: string, color?: Color): void {
if (color !== undefined) {
const coloredText = this._colorsMap[color](text);
console.log(coloredText);
} else {
console.log(text);
}
}

logVerbose(text: string): void {
logRed(text: string): void {
this.log(text, Color.Red)
}

logGreen(text: string): void {
this.log(text, Color.Green)
}

logVerbose(text: string, color?: Color): void {
if (this._options.verbose) {
console.log(text);
this.log(text, color);
}
}

logDebug(text: string): void {
logDebug(text: string, color?: Color): void {
if (this._options.debug) {
console.log(text);
this.log(text, color);
}
}
}
14 changes: 10 additions & 4 deletions gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as glob from "glob";
import * as gulp from "gulp";
import * as path from "path";
import { argv } from "yargs";
import { findAzureRestApiSpecsRepository, findSdkDirectory, findMissingSdks, copyExistingNodeJsReadme } from "./.scripts/generate-sdks";
import { findAzureRestApiSpecsRepository, findSdkDirectory, findMissingSdks, copyExistingNodeJsReadme, updateTypeScriptReadmeFile, saveContentToFile } from "./.scripts/generate-sdks";

const azureSDKForJSRepoRoot: string = __dirname;
const azureRestAPISpecsRoot: string = argv['azure-rest-api-specs-root'] || path.resolve(azureSDKForJSRepoRoot, '..', 'azure-rest-api-specs');
Expand Down Expand Up @@ -269,14 +269,20 @@ gulp.task("generate-ts-readme", async () => {
try {
console.log(`Passed arguments: ${process.argv}`);

const azureRestApiSpecsRepository = await findAzureRestApiSpecsRepository();
const azureRestApiSpecsRepository: string = await findAzureRestApiSpecsRepository();
console.log(`Found azure-rest-api-specs repository in ${azureRestApiSpecsRepository}`);

const sdkPath = await findSdkDirectory(azureRestApiSpecsRepository);
const sdkPath: string = await findSdkDirectory(azureRestApiSpecsRepository);
console.log(`Found specification in ${sdkPath}`);

await copyExistingNodeJsReadme(sdkPath);
const typescriptReadmePath: string = await copyExistingNodeJsReadme(sdkPath);
console.log(`Copied readme file successfully`);

const newContent: string = await updateTypeScriptReadmeFile(typescriptReadmePath);
console.log(`Generated content of the new readme file successfully`);

await saveContentToFile(typescriptReadmePath, newContent);
console.log(`Content saved successfully to ${typescriptReadmePath}`);
}
catch (error) {
console.error(error);
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
},
"devDependencies": {
"@types/colors": "^1.2.1",
"@types/js-yaml": "^3.11.2",
"@types/minimist": "^1.2.0",
"@types/node": "^10.11.4",
"colors": "^1.3.2",
"fs": "0.0.1-security",
"gulp": "^3.9.1",
"js-yaml": "^3.12.0",
"minimist": "^1.2.0",
"path": "^0.12.7",
"ts-node": "^7.0.1",
Expand Down

0 comments on commit 04bd3f4

Please sign in to comment.