How to write a blog publish link CLI with Yarrrgs!
Tags: showdev, gatsby, beginners, javascript
Published: 2019-03-22 08:53:25

---
title: How to write a blog publish link CLI with Yarrrgs!
published: true
description: Short tutorial on how to write a simple CLI tool - opening browser. To publish your blog link.
tags: showdev, gatsbyjs, beginners, javascript
canonical_url: https://blog.graphqleditor.com/blog-publish-tools-inside-gatsby-blog/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/5tf5mofyn19z80bq9p53.gif
---

## Introduction

Hello, today I will write a little bit about tooling. 2 weeks ago I thought about starting this blog. I asked my friend who blogs what blog engine should I use. His answer was rather surprising as he told me I should have used static website and commit blog posts as pull requests to it :O.

## Searching for the perfect solution

So, I started exploring the internet to find the best blog layout ( reactjs ) tool to write my static blog. I was able to dig out `gatsby starter blog` from hundreds of Chinese repos which GitHub is flooded with right now. At the moment I created this blog I had no experience with Gatsby ecosystem but it looked promising for me.

## Running

Running this kind of Gatsby package required me only to install `gatsby-cli` and run the command `gatsby develop`. Pretty easy? Huh?

## Modifications

I decided to add some tweaks to this simple blog package as it was a really pure blog with one author. So to add other authors( who I don't have yet :( ) I added authors folder, so to add you as an author you need to create a folder with your name and create `index.js` file with this kind of content inside it:

```js
export const Artur = {
  photo: require('./Artur.jpeg'),
  desc:
    'GraphQL passionate. Code generation guru. Short code lover. Father. CTO. CEO.',
  name: 'Artur Czemiel',
  email: 'aexol@aexol.com',
}
```

and add of course this line to `authors/index.js` :

```js
import { Artur } from './Artur'
export const Authors = {
  Artur,
}
```

Later on, you can use it inside your blog post.

## How to add your blog post

Adding your blog post is pretty easy though. Again you have to create a folder inside pages folder with blog post slug-like `my-very-interesting-article`. Add an `index.md` file to it with this kind of header which is formatted by `graymatter` package then:
```yaml
---
title: My very interesting article
date: '2018-10-27T13:23:04.284Z'
author: Artur
---
```
ł
That's it. After writing the article you just submit pull request to your fork. I merge the pull request and publish your article to the website.

## Publish tools

Sometimes I am kinda lazy person. I added small publish CLI to this project, which automatically using `opn` opens the browser with prefilled URL and title fields for: `reddit` `LinkedIn` `twitter` `hackernews`. So it is much easier to share your blog posts from this blog. It lives in `bin/index.js` folder of this blog and uses `yargs` and `inquirer` and `graymatter` which I mentioned before.

Here is the code

```js
const yargs = require('yargs')
const fs = require('fs')
const inquirer = require('inquirer')
const opn = require('./opn')
const matter = require('gray-matter')

const HOSTNAME = 'https://blog.graphqleditor.com'
const pagesDirectory = __dirname + '/../src/pages'
const reddits = [
  'typescript',
  'javascript',
  'reactnative',
  'reactjs',
  'reactxp',
  'node',
  'webdev',
  'graphql',
  'programming',
  'technology',
  'startups',
  'learnprogramming',
  'marketing',
  'entrepreneur',
  'golang',
  'ruby',
  'dotnet',
  'java',
  'python'
].sort()
const voats = ['technology']
const mediums = [
  {
    name: 'voat',
    fn: ({ url, title }) =>
      inquirer
        .prompt([
          {
            type: 'list',
            name: 'voat',
            message: 'What voat you would like to publish to?',
            choices: voats,
          },
        ])
        .then(answers =>
          submit({
            medium: 'voat',
            reddit: answers.voat,
            title,
            url,
          })
        ),
  },
  {
    name: 'reddit',
    fn: ({ url, title }) =>
      inquirer
        .prompt([
          {
            type: 'list',
            name: 'reddit',
            message: 'What reddit you would like to publish to?',
            choices: reddits,
          },
        ])
        .then(answers =>
          submit({
            medium: 'reddit',
            reddit: answers.reddit,
            title,
            url,
          })
        ),
  },
  {
    name: 'hackerNews',
    fn: ({ url, title }) =>
      submit({
        medium: 'hackerNews',
        title,
        url,
      }),
  },
  {
    name: 'linkedIn',
    fn: ({ url, title }) =>
      submit({
        medium: 'linkedIn',
        title,
        url,
      }),
  },
  {
    name: 'twitter',
    fn: ({ url, title }) =>
      submit({
        medium: 'twitter',
        title,
        url,
      }),
  },
]
const submit = ({ medium, title, url, reddit }) =>
  opn(
    {
      voat: `https://voat.co/submit?linkpost=true&title=${title}&url=${url}&subverse=${reddit}`,
      hackerNews: `http://news.ycombinator.com/submitlink?u=${url}&t=${encodeURIComponent(
        title
      )}`,
      reddit: `https://www.reddit.com/r/${reddit}/submit?title=${encodeURIComponent(
        title
      )}&url=${url}`,
      linkedIn: `https://www.linkedin.com/shareArticle?mini=true&url=${url}&source=${encodeURIComponent(
        HOSTNAME
      )}`,
      twitter: `http://twitter.com/share?url=${url}&text=${encodeURIComponent(
        title
      )}`,
    }[medium],
    {
      wait: false,
    }
  )

const argv = () =>
  yargs
    .command(
      'publish',
      'Publish your blog post for different mediums',
      {},
      async argv => {
        const pageNames = fs
          .readdirSync(pagesDirectory)
          .filter(page =>
            fs.lstatSync(`${pagesDirectory}/${page}`).isDirectory()
          )
        const pages = pageNames.map(page => ({
          url: `${HOSTNAME}/${page}`,
          title: matter(
            fs.readFileSync([pagesDirectory, page, 'index.md'].join('/'))
          ).data.title,
        }))
        inquirer
          .prompt([
            {
              type: 'list',
              name: 'page',
              message: 'Which page would you like to publish',
              choices: pages.map(p => p.title),
            },
          ])
          .then(answers => pages.find(p => p.title === answers.page))
          .then(page =>
            inquirer
              .prompt([
                {
                  type: 'list',
                  name: 'medium',
                  message: 'What medium you would like to publish to?',
                  choices: mediums.map(m => m.name).concat('All mediums'),
                },
              ])
              .then(
                answers =>
                  answers.medium === 'All mediums'
                    ? Promise.all(
                        mediums
                          .filter(m => m.name !== 'reddit' && m.name !== 'voat')
                          .map(m => m.fn(page))
                      )
                    : mediums
                        .find(m => m.name === answers.medium)
                        .fn(page)
                        .then(proc =>
                          inquirer
                            .prompt([
                              {
                                type: 'list',
                                name: 'again',
                                message: 'What next?',
                                choices: ['Exit', 'Next Action'],
                              },
                            ])
                            .then(({ again }) => {
                              if (again === 'Exit') {
                                return
                              }
                              return argv()
                            })
                        )
              )
          )
      }
    )
    .help().argv
argv()

```

![](https://thepracticaldev.s3.amazonaws.com/i/5tf5mofyn19z80bq9p53.gif)

After that, it opens a window so I can post on Reddit. Simple and beautiful!

![](https://thepracticaldev.s3.amazonaws.com/i/qvzxn3ewmph8dyu3li0t.png)