Ronniegeraghty inventory sdk updates 20 (#6219)

* Updates for Monitor

* updating the inventory scripts and how they create missing entries from the specs repo
This commit is contained in:
Ronnie Geraghty 2023-06-07 10:48:17 -07:00 коммит произвёл GitHub
Родитель b822dabddb
Коммит ab835310ad
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 1840 добавлений и 94 удалений

Просмотреть файл

@ -73,7 +73,7 @@ steps:
displayName: Installing Inventory Dashboard Data Scripts Dependencies
- bash: |
npm run start
npm run start $(System.DefaultWorkingDirectory)/azure-rest-api-specs/specification
workingDirectory: $(AzureSDKClonePath)/eng/scripts/inventory-dashboard
displayName: Run Inventory Dashboard Data Scripts

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -13,6 +13,9 @@
"Cognitive Services|Custom Vision Training":["data"],
"Cognitive Services|Custom Vision Prediction":["data"],
"Custom Web Search": ["data", "mgmt"],
"Common Types": ["data", "mgmt"],
"Compute|quickstart-templates":["data"],
"contosowidgetmanager":["data"],
"Entity Search": ["data", "mgmt"],
"Cognitive Services|Face":["data"],
"Functions": ["data"],
@ -21,6 +24,7 @@
"Kinect Developer Kit":["data", "mgmt"],
"Local Search": ["data", "mgmt"],
"News Search": ["data", "mgmt"],
"Monitor|Operational Insights": ["data"],
"Power BI": ["data", "mgmt"],
"Service Fabric": ["data"],
"Solutions":["mgmt"],

Просмотреть файл

@ -7,12 +7,14 @@ import {
import { Logger } from './logger';
import _serviceNameMap from "../data-and-rules/serviceNameMap.json";
import _servicesToHide from "../data-and-rules/servicesToHide.json";
import _apiSpecMap from '../data-and-rules/apiSpecMap.json';
import path from "path";
import fs from 'fs';
const log = Logger.getInstance();
const specsDirPath = path.join(__dirname, '../../../../../azure-rest-api-specs/specification');
//const specsDirPath = path.join(__dirname, '../../../../../azure-rest-api-specs/specification');
const serviceNameMap: any = _serviceNameMap;
const servicesToHide: any = _servicesToHide;
const apiSpecMap: any = _apiSpecMap;
/**
@ -20,7 +22,7 @@ const servicesToHide: any = _servicesToHide;
* @param packages A map of packages after being formatted
* @returns a map of packages with empty entries added
*/
export default async function addEmptyDataPoints(packages: PackageList): Promise<PackageList> {
export default async function addEmptyDataPoints(packages: PackageList, apiSpecsDirPath: string): Promise<PackageList> {
// Add missing sdks when sdks for other languages are found
const additionalPackages: PackageList = {};
for (let key in packages) {
@ -66,7 +68,7 @@ export default async function addEmptyDataPoints(packages: PackageList): Promise
// add new empty packages to package list and return
packages = { ...packages, ...additionalPackages };
// add empty packages to package list if service API exists
packages = { ...packages, ...(await getServicesFromSpecRepo(packages)) };
packages = { ...packages, ...(await getServicesFromSpecRepo(packages, apiSpecsDirPath)) };
return packages;
}
@ -77,78 +79,182 @@ export default async function addEmptyDataPoints(packages: PackageList): Promise
* @param packages a Package List of already existing packages, used to stop the function from creating duplicate packages
* @returns a Package List of empty packages for apis that exist but don't already have a package.
*/
async function getServicesFromSpecRepo(packages: PackageList): Promise<PackageList> {
const additionalPackages: PackageList = {}; // empty pkgs collected from specs repo to add
// async function getServicesFromSpecRepoOLD(packages: PackageList, apiSpecsDirPath: string): Promise<PackageList> {
// const additionalPackages: PackageList = {}; // empty pkgs collected from specs repo to add
// // get list of service dirs from specs dir
// const serviceSpecDirs = fs.readdirSync(apiSpecsDirPath);
// for (let serviceSpecDir of serviceSpecDirs) {
// // determine service name and SDK name
// let serviceName: string = "";
// let sdkName: string = "";
// if (typeof serviceNameMap[serviceSpecDir] === 'string' && serviceNameMap[serviceSpecDir].split("|").length > 1) {
// [serviceName, sdkName] = serviceNameMap[serviceSpecDir].split("|");
// } else {
// serviceName = serviceNameMap[serviceSpecDir] === undefined ? serviceSpecDir : serviceNameMap[serviceSpecDir];
// sdkName = serviceName;
// }
// // test if service spec dir is a dir, if not move on.
// if (!fs.lstatSync(path.join(apiSpecsDirPath, serviceSpecDir)).isDirectory()) continue;
// // list of plane dirs in service spec dir, should be either data-plane and/or resource-manager
// let planeSpecDirs: string[] = fs.readdirSync(path.join(apiSpecsDirPath, serviceSpecDir));
// // loop through plane dirs in the service spec dir
// for (let planeSpecDir of planeSpecDirs) {
// // determine plane and SDK name
// let plane: Plane = "UNABLE TO BE DETERMINED";
// if (planeSpecDir === 'data-plane') { plane = "data"; }
// else if (planeSpecDir === 'resource-manager') { plane = 'mgmt'; sdkName = `Resource Management - ${sdkName}`; }
// // skip service api spec if it's in the list of services to hide
// // Ignore Services Plane pairs that are specified in servicesToHide.json
// if (servicesToHide[serviceName] !== undefined) {
// if (Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) {
// continue;
// }
// }
// // Ignore Service|SDK Plane pairs that are specified in servicesToHide.json
// if (servicesToHide[`${serviceName}|${sdkName}`] !== undefined) {
// if (Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane)) {
// continue;
// }
// }
// // check if stable spec exists
// const planeSpecDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceSpecDir, planeSpecDir));
// const filteredPlaneSpecDirContents = planeSpecDirContents.filter(s => s.startsWith('Microsoft.'));
// if (filteredPlaneSpecDirContents.length <= 0) { log.warn(`${serviceSpecDir}/${planeSpecDir} has no dir that starts with "Microsoft."`); }
// else {
// const microsoftDir = filteredPlaneSpecDirContents[0];
// const microsoftDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceSpecDir, planeSpecDir, microsoftDir));
// const filteredMicrosoftDirContents = microsoftDirContents.filter(s => s === "stable");
// if (filteredMicrosoftDirContents.length <= 0) { log.info(`No stable API Spec found for ${serviceSpecDir}/${planeSpecDir}`); }
// else {
// // stable spec does exist
// // check if package exists for each language, if not add empty entry
// for (let language of Tier1Languages) {
// // create pkg key
// const key = (serviceName + sdkName + plane + language).toLowerCase();
// // If package doesn't exist in list already, add it.
// if (packages[key] === undefined && additionalPackages[key] === undefined) {
// additionalPackages[key] = {
// Service: serviceName,
// ServiceId: 0,
// SDK: sdkName,
// Plane: plane,
// Language: language,
// Track1: TrackSpecificsDefault,
// Track2: { ...TrackSpecificsDefault, Package: `Missing: Created from API in specs repo: ${serviceSpecDir}/${}` },
// PercentComplete: undefined,
// LatestRelease: ''
// };
// log.info(`Adding Empty Package from Specs Repo.\n\tEmpty Package: ${JSON.stringify(additionalPackages[key])}\n\tREST Spec Dir: ${path.join(apiSpecsDirPath, serviceSpecDir, planeSpecDir)}`);
// }
// }
// }
// }
// }
// }
// return additionalPackages;
// }
/** Determines if there are azure apis without SDKs of the Tier 1 Languages and creates a Package List of empty packages for said apis.
* The function scans through a local copy of the Azure/azure-rest-api-specs repo to determine if SDKs are missing.
* @param packages a Package List of already existing packages, used to stop the function from creating duplicate packages
* @returns a Package List of empty packages for apis that exist but don't already have a package.
*/
async function getServicesFromSpecRepo(packages: PackageList, apiSpecsDirPath: string): Promise<PackageList> {
// empty PackageList to be returned
const additionalPackages: PackageList = {};
// get list of service dirs from specs dir
const serviceSpecDirs = fs.readdirSync(specsDirPath);
for (let serviceSpecDir of serviceSpecDirs) {
// determine service name and SDK name
const serviceDirs = fs.readdirSync(apiSpecsDirPath);
// loop through service dirs
for (let serviceDir of serviceDirs) {
let serviceName: string = "";
let sdkName: string = "";
if (typeof serviceNameMap[serviceSpecDir] === 'string' && serviceNameMap[serviceSpecDir].split("|").length > 1) {
[serviceName, sdkName] = serviceNameMap[serviceSpecDir].split("|");
// if the the serviceDir maps to a key in ../data-and-rules/apiSpecMap.json, use the service-display-name property from the value object as the serviceName
if (typeof apiSpecMap[serviceDir] === 'object' && apiSpecMap[serviceDir].hasOwnProperty('service-display-name')) {
serviceName = apiSpecMap[serviceDir]['service-display-name'];
} else {
serviceName = serviceNameMap[serviceSpecDir] === undefined ? serviceSpecDir : serviceNameMap[serviceSpecDir];
sdkName = serviceName;
serviceName = serviceDir;
}
// test if service spec dir is a dir, if not move on.
if (!fs.lstatSync(path.join(specsDirPath, serviceSpecDir)).isDirectory()) continue;
// list of plane dirs in service spec dir, should be either data-plane and/or resource-manager
let planeSpecDirs: string[] = fs.readdirSync(path.join(specsDirPath, serviceSpecDir));
// loop through plane dirs in the service spec dir
for (let planeSpecDir of planeSpecDirs) {
// determine plane and SDK name
let plane: Plane = "UNABLE TO BE DETERMINED";
if (planeSpecDir === 'data-plane') { plane = "data"; }
else if (planeSpecDir === 'resource-manager') { plane = 'mgmt'; sdkName = `Resource Management - ${sdkName}`; }
// skip service api spec if it's in the list of services to hide
// Ignore Services Plane pairs that are specified in servicesToHide.json
if (servicesToHide[serviceName] !== undefined) {
if (Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) {
continue;
// if specDir is a dir, read it's contents and loop through them
if (fs.lstatSync(path.join(apiSpecsDirPath, serviceDir)).isDirectory()) {
const apiSpecDirs = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir));
for (let apiSpecDir of apiSpecDirs) {
// determine SDK name
let sdkName: string = "Unable to determine Service Name";
// if the serviceDir maps to a key in ../data-and-rules/apiSpecMap.json, and it's value object has an api-display-name property, with a property that matches the apiSpecDir, use the value of that property as the sdkName
log.atn(`apiSpecMap[serviceDir]: ${JSON.stringify(apiSpecMap[serviceDir])}`);
log.atn(`typeof apiSpecMap[serviceDir]: ${typeof apiSpecMap[serviceDir]}`);
log.atn(`apiSpecMap[serviceDir].hasOwnProperty('api-display-names'): ${apiSpecMap[serviceDir].hasOwnProperty('api-display-names')}`);
log.atn(`typeof apiSpecMap[serviceDir]['api-display-names']: ${typeof apiSpecMap[serviceDir]['api-display-names']}`);
log.atn(`apiSpecMap[serviceDir]['api-display-names'].hasOwnProperty(apiSpecDir): ${apiSpecMap[serviceDir]['api-display-names'].hasOwnProperty(apiSpecDir)}`);
if (typeof apiSpecMap[serviceDir] === 'object' && apiSpecMap[serviceDir].hasOwnProperty('api-display-names') && typeof apiSpecMap[serviceDir]['api-display-names'] === 'object' && apiSpecMap[serviceDir]['api-display-names'].hasOwnProperty(apiSpecDir)) {
log.atn(`apiSpecMap[serviceDir]['api-display-names'][apiSpecDir]: ${apiSpecMap[serviceDir]['api-display-names'][apiSpecDir]}`);
sdkName = apiSpecMap[serviceDir]['api-display-names'][apiSpecDir];
} else {
// if apiSpecDir is data-plane or resource-manager, sdkName should be the same as serviceName, else it should be the same as apiSpecDir
sdkName = apiSpecDir === 'data-plane' || apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management' ? serviceName : apiSpecDir;
}
}
// Ignore Service|SDK Plane pairs that are specified in servicesToHide.json
if (servicesToHide[`${serviceName}|${sdkName}`] !== undefined) {
if (Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane)) {
continue;
}
}
// check if stable spec exists
const planeSpecDirContents = fs.readdirSync(path.join(specsDirPath, serviceSpecDir, planeSpecDir));
const filteredPlaneSpecDirContents = planeSpecDirContents.filter(s => s.startsWith('Microsoft.'));
if (filteredPlaneSpecDirContents.length <= 0) { log.warn(`${serviceSpecDir}/${planeSpecDir} has no dir that starts with "Microsoft."`); }
else {
const microsoftDir = filteredPlaneSpecDirContents[0];
const microsoftDirContents = fs.readdirSync(path.join(specsDirPath, serviceSpecDir, planeSpecDir, microsoftDir));
const filteredMicrosoftDirContents = microsoftDirContents.filter(s => s === "stable");
if (filteredMicrosoftDirContents.length <= 0) { log.info(`No stable API Spec found for ${serviceSpecDir}/${planeSpecDir}`); }
// Determine the plane
let plane: Plane = "UNABLE TO BE DETERMINED";
if (apiSpecDir === 'data-plane') { plane = "data"; }
else if (apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management') { plane = 'mgmt'; sdkName = `Resource Management - ${sdkName}`; }
// TODO - add way of checking TypeSpec api spec dirs plane
else {
// stable spec does exist
// check if package exists for each language, if not add empty entry
for (let language of Tier1Languages) {
// create pkg key
const key = (serviceName + sdkName + plane + language).toLowerCase();
// If package doesn't exist in list already, add it.
if (packages[key] === undefined && additionalPackages[key] === undefined) {
additionalPackages[key] = {
Service: serviceName,
ServiceId: 0,
SDK: sdkName,
Plane: plane,
Language: language,
Track1: TrackSpecificsDefault,
Track2: { ...TrackSpecificsDefault, Package: `Missing: Created from API in specs repo: ${serviceSpecDir}` },
PercentComplete: undefined,
LatestRelease: ''
};
log.info(`Adding Empty Package from Specs Repo.\n\tEmpty Package: ${JSON.stringify(additionalPackages[key])}\n\tREST Spec Dir: ${specsDirPath}`);
}
// if apiSpecDir ends in .management regardless of case, print out attention log
if (apiSpecDir.toLowerCase().endsWith('.management')) {
plane = 'mgmt';
sdkName = `Resource Management - ${sdkName}`;
} else {
plane = 'data';
}
}
// skip service api spec if it's in the list of services to hide
if ((servicesToHide[serviceName] !== undefined && Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) || (servicesToHide[`${serviceName}|${sdkName}`] !== undefined && Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane))) {
if ((Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) || (Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane))) {
continue;
}
}
// Check if stable spec exists
const apiSpecDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir, apiSpecDir));
if (apiSpecDir === 'data-plane' || apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management') {
const filteredApiSpecDirContents = apiSpecDirContents.filter(s => s.startsWith('Microsoft.'));
if (filteredApiSpecDirContents.length <= 0) { log.warn(`${serviceDir}/${apiSpecDir} has no dir that starts with "Microsoft."`); }
else {
const microsoftDir = filteredApiSpecDirContents[0];
const microsoftDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir, apiSpecDir, microsoftDir));
const filteredMicrosoftDirContents = microsoftDirContents.filter(s => s === "stable");
// If no stable api was found skip
if (filteredMicrosoftDirContents.length <= 0) { log.info(`No stable API Spec found for ${serviceDir}/${apiSpecDir}`); continue; }
}
} else {
//TODO - check if TypeSpec api has stable version, if not skip
}
// loop through Tier 1 languages and create empty package if it doesn't exist
for (let language of Tier1Languages) {
// create pkg key
const key = (serviceName + sdkName + plane + language).toLowerCase();
// If package doesn't exist in list already, add it.
if (packages[key] === undefined && additionalPackages[key] === undefined) {
additionalPackages[key] = {
Service: serviceName,
ServiceId: 0,
SDK: sdkName,
Plane: plane,
Language: language,
Track1: TrackSpecificsDefault,
Track2: { ...TrackSpecificsDefault, Package: `Missing: Created from API in specs repo: ${serviceDir}/${apiSpecDir}` },
PercentComplete: undefined,
LatestRelease: ''
};
log.info(`Adding Empty Package from Specs Repo.\n\tEmpty Package: ${JSON.stringify(additionalPackages[key])}\n\tREST Spec Dir: ${serviceDir}/${apiSpecDir}`);
}
}
}
}
}
return additionalPackages;
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// A script that reads the directories in ../azure-rest-api-specs/specification and outputs the directories in a JSON file with the following format:
// {
// "directory-name": {
// "service-display-name":"name of directory",
// "api-display-names": {
// "subdirectory-names": "api-display-name"
// },
// },
// }
// If the directory-name maps to a key in ../data-and-rules/serviceNameMap.json, the service-display-name will be the value of that key. If the value contains a "|", the service-display-name should be the string before the "|". If not, it will be the directory-name.
// If the subdirectory name is data-plane or resource-manager, the api-display-name will be the same as the service-display-name, but if the directory-name maps to a key in ../data-and-rules/serviceNameMap.json, the api-display-name will be the value of that key. If the value contains a "|", the api-display-name should be the string after the "|".
// If the subdirectory name is neither resource-manager nor data-plane, the api-display-name will be the same as the subdirectory name.
const fs = require("fs");
const path = require("path");
const serviceNameMap = require("../data-and-rules/serviceNameMap.json");
const apiSpecRepoDir = path.join(__dirname, "..", "..", "..","..", "..", "azure-rest-api-specs", "specification");
const apiSpecRepoDirReadingToolOutput = path.join(__dirname,"..", "data-and-rules", "apiSpecMap.json");
const jsonOutput = {};
const specDirs = fs.readdirSync(apiSpecRepoDir);
specDirs.forEach(specDir => {
const specDirPath = path.join(apiSpecRepoDir, specDir);
const specDirStats = fs.statSync(specDirPath);
if (specDirStats.isDirectory()) {
const serviceDisplayName = getServiceDisplayName(specDir);
const apiDisplayNames = getApiDisplayNames(specDirPath, specDir);
jsonOutput[specDir] = {
"service-display-name": serviceDisplayName,
"api-display-names": apiDisplayNames
};
}
});
fs.writeFileSync(apiSpecRepoDirReadingToolOutput, JSON.stringify(jsonOutput, null, 4));
function getServiceDisplayName(specDir) {
if (serviceNameMap[specDir]) {
if (serviceNameMap[specDir].includes("|")) {
return serviceNameMap[specDir].split("|")[0];
} else {
return serviceNameMap[specDir];
}
} else {
return specDir;
}
}
function getApiDisplayNames(specDirPath, specDir) {
const apiDisplayNames = {};
const subDirs = fs.readdirSync(specDirPath);
subDirs.forEach(subDir => {
if(subDir === "data-plane" || subDir === "resource-manager") {
if(serviceNameMap[specDir]) {
if (serviceNameMap[specDir].includes("|")) {
apiDisplayNames[subDir] = serviceNameMap[specDir].split("|")[1];
} else {
apiDisplayNames[subDir] = serviceNameMap[specDir];
}
} else {
apiDisplayNames[subDir] = specDir;
}
}else {
apiDisplayNames[subDir] = subDir;
}
});
return apiDisplayNames;
}

Просмотреть файл

@ -0,0 +1,20 @@
const csvToJSON = require("csvtojson");
const path = require("path");
const inventoryCSVPath = path.join(__dirname,"..", "..", "..", "..", "_data", "releases", "inventory", "inventory.csv");
getInventoryStats();
async function getInventoryStats() {
const inventoryJSON = await csvToJSON().fromFile(inventoryCSVPath);
//Print out the number of objects in the inventoryJSON array with distinct values for 'Service'
console.log(`There are ${inventoryJSON.filter((item, index, self) => self.findIndex(t => t.Service === item.Service) === index).length} distinct services in the inventory.`);
//Print out and number the distinct values for 'Service'. Exclude any services with Core in the name regardless of case.
console.log(`The distinct services are: ${inventoryJSON.filter((item, index, self) => self.findIndex(t => t.Service === item.Service) === index).filter((item) => !item.Service.toLowerCase().includes("core")).map((item, index) => `${index + 1}. ${item.Service}`).join(", ")}.`);
// Print out the number of objects in the inventoryJSON array with a Plane value of 'mgmt` and who's Track2 value has a ColorCode value of '10'
console.log(`There are ${inventoryJSON.filter((item) => item.Plane === "mgmt" && item.Track2.ColorCode === "10").length} objects in the inventory with a Plane value of 'mgmt' and a Track2 value of '10'.`);
// Print out the number of objects in the inventoryJSON array with a Plane value of 'mgmt` and who's Track2 value has a ColorCode value of '3'
console.log(`There are ${inventoryJSON.filter((item) => item.Plane === "mgmt" && item.Track2.ColorCode === "3").length} objects in the inventory with a Plane value of 'mgmt' and a Track2 value of '3'.`);
// Print out the number of objects in the inventoryJSON array with a Plane value of 'mgmt` and who's Track2 value has a ColorCode value of '1' or '2'
console.log(`There are ${inventoryJSON.filter((item) => item.Plane === "mgmt" && (item.Track2.ColorCode === "1" || item.Track2.ColorCode === "2")).length} objects in the inventory with a Plane value of 'mgmt' and a Track2 value of '1' or '2'.`);
}

Просмотреть файл

@ -9,36 +9,39 @@ import exceptionHandler from "./exceptionHandler";
import addDashboardMetaData from "./dashboardMetaData";
const log = Logger.getInstance();
//Get two inputs from command line for csvDirPath and apiSpecsDirPath
const apiSpecsDirPath = process.argv[2];
// Main entry point for data collection and data formatting of SDK Package Inventory Data
async function main() {
// Pull in csv data from release CSVs and convert to array of Objects
const csvData = await collectCSVData();
// Format JSON Objects
let formattedCSVData = formatReleaseCSVData(csvData);
// Add empty data points, ex: if data plane SDK is missing.
formattedCSVData = await addEmptyDataPoints(formattedCSVData);
// Add color code and completeness percent
formattedCSVData = addDashboardMetaData(formattedCSVData);
// Add exception handling
formattedCSVData = exceptionHandler(formattedCSVData);
// Turn package map into a package array
const formattedPackageArr = [];
for (let pkgKey in formattedCSVData) {
formattedPackageArr.push(formattedCSVData[pkgKey]);
}
// Write Formatted Object to CSV File
json2csv(formattedPackageArr, (err, csv) => {
if (err) {
log.err(`Error Writing to CSV. Error: ${err}`);
} else if (csv) {
fs.writeFileSync(
path.join(__dirname, "../../../../_data/releases/inventory/inventory.csv"),
csv
);
} else {
log.err(`CSV is undefined`);
// Pull in csv data from release CSVs and convert to array of Objects
const csvData = await collectCSVData();
// Format JSON Objects
let formattedCSVData = formatReleaseCSVData(csvData);
// Add empty data points, ex: if data plane SDK is missing.
formattedCSVData = await addEmptyDataPoints(formattedCSVData, apiSpecsDirPath);
// Add color code and completeness percent
formattedCSVData = addDashboardMetaData(formattedCSVData);
// Add exception handling
formattedCSVData = exceptionHandler(formattedCSVData);
// Turn package map into a package array
const formattedPackageArr = [];
for (let pkgKey in formattedCSVData) {
formattedPackageArr.push(formattedCSVData[pkgKey]);
}
});
// Write Formatted Object to CSV File
json2csv(formattedPackageArr, (err, csv) => {
if (err) {
log.err(`Error Writing to CSV. Error: ${err}`);
} else if (csv) {
fs.writeFileSync(
path.join(__dirname, "../../../../_data/releases/inventory/inventory.csv"),
csv
);
} else {
log.err(`CSV is undefined`);
}
});
}
main();