From f72cb3f1cf61b2f144e30a9c4555527215760609 Mon Sep 17 00:00:00 2001 From: Giacomo Cerquone Date: Tue, 23 Mar 2021 14:54:28 +0100 Subject: [PATCH] feat: add possibility to extract the model from a specific md file --- README.md | 2 +- index.js | 121 ++++++++++++++++++++++++++++-------------- package.json | 2 +- src/fetchFilenames.js | 17 ++++++ src/fetchMds.js | 16 +----- 5 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 src/fetchFilenames.js diff --git a/README.md b/README.md index 087c7c5..5e9e11a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ It also gives you an admin UI to create instances of these entities. They also h ## What does this migrator do? -Basically, you can give it a folder full of MD files, and it will try to create a "Post" entity on your GraphCMS instance, and it will just create as many posts as the number of your MD files with their content in it. (it will recursively find the files between all your folders). +You can give it a folder full of MD files, and it will try to create a "Post" entity on your GraphCMS instance, and it will create as many posts as the number of your MD files with their content in it. (it will recursively find the files between all your folders). It also uploads your media and the thumbnail of every post in the pre-configured Asset model in GraphCMS.

**This package will try to recreate the model from the first markdown it encounters.**
It means that if you have markdowns with different YAML sections, you need to create two separate folders where you'll run this migrator.
diff --git a/index.js b/index.js index 85f01a2..a66e31f 100755 --- a/index.js +++ b/index.js @@ -8,6 +8,8 @@ const fetchMds = require("./src/fetchMds"); const extractModel = require("./src/extractModel"); const uploadMds = require("./src/uploadMds"); const { capitalize, logger, spinner, restartSpinner } = require("./src/utils"); +const { fetchFilenames } = require("./src/fetchFilenames"); +const path = require("path"); const argv = hideBin(process.argv); @@ -15,37 +17,50 @@ yargs(argv).command( "$0 [path] [url] [token]", "start the migration of the md files in the specified path.", (yargs) => { - return yargs - .positional("path", { - describe: "Path of the folder of the md files to migrate.", - }) - .option("url", { - alias: "u", - type: "string", - description: "Your graphCMS URL", - }) - .option("publish", { - alias: "p", - type: "boolean", - description: - "Set this if you want your post to be published (defaults to draft posts)", - }) - .option("token", { - alias: "t", - type: "string", - description: "Your graphCMS token", - }) - .option("thumb_field", { - type: "string", - description: - 'The name of the yaml field to recognize as a post thumbnail (it will be uploaded automatically to the "Asset" model)', - }) - .option("exclude", { - alias: "exc", - type: "string", - description: - "Comma separated list of fields to exclude from your mds frontmatter", - }); + return ( + yargs + .option("path", { + alias: "p", + type: "string", + description: "Path of the folder of the md files to migrate.", + }) + .option("url", { + alias: "u", + type: "string", + description: "Your graphCMS URL", + }) + // .option("publish", { + // alias: "p", + // type: "boolean", + // description: + // "Set this if you want your post to be published (defaults to draft posts)", + // }) + .option("token", { + alias: "t", + type: "string", + description: "Your graphCMS token", + }) + .option("thumb-field", { + type: "string", + description: + 'The name of the yaml field to recognize as a post thumbnail (it will be uploaded automatically to the "Asset" model)', + }) + .option("exclude", { + type: "string", + description: + "Comma separated list of fields to exclude from your mds frontmatter", + }) + .option("model-from", { + type: "string", + description: + 'The filename of the specific MD file to use to extract the model (you must add the ".md" extension when specifying it)', + }) + .option("model-name", { + type: "string", + description: + 'The name of the model that will be created in GraphCMS (Defaults to "Post")', + }) + ); }, async (argv) => { if (!argv.path) { @@ -58,13 +73,28 @@ yargs(argv).command( return logger.error("You must specify your graphcms token"); } - if (!argv.thumb_field) { + if (!argv["thumb-field"]) { logger.warn( "You didn't specify any yaml field to be used as post thumbnail" ); } + if (!argv["exclude"]) { + logger.warn( + "You didn't specify any yaml field to exclude, therefore all the fields will be taken" + ); + } + if (!argv["model-from"]) { + logger.warn( + "You didn't specify any MD file to extract the model from, therefore the first one will be used" + ); + } + if (!argv["model-name"]) { + logger.warn( + 'You didn\'t specify a name for the model that will be created, therefore "Post" will be used' + ); + } - const response = await prompts( + const promptsRes = await prompts( { type: "text", name: "modelName", @@ -73,27 +103,40 @@ yargs(argv).command( { onCancel: () => process.exit() } ); - if (!response.modelName) { - response.modelName = "Post"; + if (!promptsRes.modelName) { + promptsRes.modelName = "Post"; } try { restartSpinner("Fetching and parsing mds file"); - const mds = await fetchMds(argv.path); + const fileNames = await fetchFilenames(argv.path); + const mds = await fetchMds(fileNames); + if (!mds.length) { + spinner.succeed(); + logger.error("No md file found!"); + process.exit(); + } + const extractModelFrom = argv["model-from"] + ? mds[ + fileNames.findIndex( + (fN) => path.basename(fN) === argv["model-from"] + ) + ] + : mds[0]; restartSpinner("Extracting model from first md file"); - const model = extractModel(mds?.[0], argv.thumb_field); + const model = extractModel(extractModelFrom, argv.thumb_field); restartSpinner("Creating the model inside your graphCMS instance"); await createModel( argv.url, argv.token, model, - capitalize(response.modelName) + capitalize(promptsRes.modelName) ); restartSpinner("Creating the mds inside your graphCMS instance"); await buildGqlClient(argv.url, argv.token); await uploadMds( mds, - capitalize(response.modelName), + capitalize(promptsRes.modelName), argv.thumb_field, argv.token, argv.url diff --git a/package.json b/package.json index 007ff28..8e69b43 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "graphcms-markdown-migrator", "version": "0.2.0", - "description": "A CLI tool to automate the migration from markdown files to graphcms (useful for gatsby blogs for example and everything else)", + "description": "A CLI tool to automate the migration from markdown files to GraphCMS (useful for gatsby blogs for example and everything else)", "main": "index.js", "scripts": { "start": "./index.js --path ./example -u https://api-eu-central-1.graphcms.com/v2/ckml7qpvfgf6n01z28xbq03j4/master", diff --git a/src/fetchFilenames.js b/src/fetchFilenames.js new file mode 100644 index 0000000..e1a92b0 --- /dev/null +++ b/src/fetchFilenames.js @@ -0,0 +1,17 @@ +const glob = require("glob"); +const path = require("path"); + +const fetchFilenames = (mdsPath) => + new Promise((resolve, reject) => { + const joinedPath = path.join(process.cwd(), mdsPath, "**/*.md"); + glob(joinedPath, function (er, files) { + if (er) { + return reject(er); + } + resolve(files); + }); + }); + +module.exports = { + fetchFilenames, +}; diff --git a/src/fetchMds.js b/src/fetchMds.js index 2e4a951..f2d13b2 100644 --- a/src/fetchMds.js +++ b/src/fetchMds.js @@ -1,22 +1,8 @@ -const glob = require("glob"); -const path = require("path"); const process = require("process"); const fs = require("fs/promises"); const { spinner, logger } = require("./utils"); -const fetchFilenames = (mdsPath) => - new Promise((resolve, reject) => { - const joinedPath = path.join(process.cwd(), mdsPath, "**/*.md"); - glob(joinedPath, function (er, files) { - if (er) { - return reject(er); - } - resolve(files); - }); - }); - -const fetchMds = async (mdsPath) => { - const fileNames = await fetchFilenames(mdsPath); +const fetchMds = async (fileNames) => { try { const readMds = await Promise.all( fileNames.map((fN) => fs.readFile(fN, "utf8"))