Skip to content

Commit

Permalink
feat: add possibility to extract the model from a specific md file
Browse files Browse the repository at this point in the history
  • Loading branch information
giacomocerquone committed Mar 23, 2021
1 parent 053aaf3 commit f72cb3f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 56 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
<br/><br/>
**This package will try to recreate the model from the first markdown it encounters.**<br/>
It means that if you have markdowns with different YAML sections, you need to create two separate folders where you'll run this migrator.<br/>
Expand Down
121 changes: 82 additions & 39 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,59 @@ 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);

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) {
Expand All @@ -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",
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
17 changes: 17 additions & 0 deletions src/fetchFilenames.js
Original file line number Diff line number Diff line change
@@ -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,
};
16 changes: 1 addition & 15 deletions src/fetchMds.js
Original file line number Diff line number Diff line change
@@ -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"))
Expand Down

0 comments on commit f72cb3f

Please sign in to comment.