Building A CLI To Help Manage GitHub Accounts, React Projects, And More…
Introducing Jarvis, my new and improved little helper
Introducing Jarvis, my new and improved little helper. I’ve been wanting to create a CLI, to help me with my workflow and day to day tasks, for a long time. This is why I created the git-cli, which I wrote about in my last piece. The git-cli works well for simple management of GitHub accounts, but I wanted it to do more. So I got comfy, put some music on, and had a think about what to do next.
I concluded that expanding on the git-cli wasn’t going to cut it and that I would create a new CLI from scratch. I decided this for a few reasons. Firstly I felt that I had written and structured it in a way that made it difficult to expand — more difficult than it needed to be. Secondly, I knew I’d written it in a way that didn’t promote code reuse. And lastly, I just felt that I could do better.
Now that I had mde the decision to create a new CLI from scratch, I had to think about exactly what I wanted it to do and how. I primarily develop React apps that are deployed on Google App Engine, use Firebase Functions and Firestore for the back-end, and have static files stored on AWS S3. I also regularly need to switch between multiple GitHub accounts, Google Cloud Platform accounts, and AWS accounts. With this information, I came up with the following requirements:
- Be able to create, store, update, delete, and switch between GitHub, GCP, and S3 configs easily.
- Be able to push changes to Github with one command.
- Be able to clone repos, and pull changes from GitHub with a simple command.
- Be able to deploy to Google App Engine, push to GitHub, and upload static files to S3 all with one command.
- Be able to initialise a complete boilerplate React template, initialise a git directory, install NPM packages, and build and run a dev server all with one command.
- Be able to create React components with a simple command.
I also decided I would like a way to open and search websites such as Google, NPM, GitHub, and StackOverflow from the command line. I wasn’t sure if this command would be worth it, but it turned out to be quicker than I thought and I now use it all the time.
Now that I had a list of requirements and a rough plan of how to make everything work, the only thing left to do, apart from building the CLI, was to think of a name for it. This was the easiest part because being a huge Marvel fan, there was only one real choice: Jarvis.
I decided to tackle the config management part of the CLI first, because most of the other features would rely on this. I wanted the ability to create new configs, update and delete specific configs, and switch configs for all of the different types of config that I use.
My main goal with managing git configs was to be able to create SSH keys, update the SSH config, and upload the public key to GitHub with as little manual work as possible. I knew that I could create the SSH keys using the ssh-keygen command, passing in all the necessary info, like the file name. I also knew that I could update the SSH config file using Node’s fs module. What I wasn’t sure about was whether I could upload the public key to GitHub, so I did some research. It turns out GitHub has a convenient API which allows new keys to be added, and also current keys to be deleted. Now I knew I could make it all work — the only thing that would have to be done manually (outside of the command line) would be creating a personal access key.
Now if you run:
jarvis config-new git
Jarvis will firs deactivate the currently active git config. It will then prompt you to enter a config id, your GitHub username and email, and the personal access token you’ve created. Jarvis does the rest for you. It stores the config locally making sure that the id is unique, creates the SSH keys, updates the SSH config, uploads the public SSH key to GitHub, and activates the config so it’s ready to use right away.
Speaking of activating the config, this is the next step. Switching between git configs with Jarvis is as easy as:
jarvis config-switch git
When this command is run, Jarvis displays a list of stored configs to choose from. All you need to do is enter the id of the config that you want to switch to and tell Jarvis what repo you are currently working on. Once you have done this, Jarvis will set the correct local and global git configs, and set the correct remote URL.
But what if, for example, you change your username? Don’t worry, I have made it nice and easy to update the stored configs. You might have already guessed what the command for this is:
jarvis config-update git
Just as with switching configs, Jarvis will ask which config you want to update. Once you have told Jarvis which config to update, it will ask for new values for all of the properties that can be changed. If you don’t want to change a specific property, press enter, and it will use the current property value.
I thought that the update command would be as simple as this, but I quickly realised there are a couple of issues. The first being that, if your username has changed, the remote URL, and local and global git configs would be wrong. This wasn’t a big issue because I could activate the config with the updated properties, and everything would be updated. The second issue was that if your username has changed, then the SSH keys and config won’t match the new username, which will cause any git requests made to fail. I decided to solve this by completely deleting the SSH keys, both locally and from GitHub, and creating new ones.
You might be wondering why I chose to delete everything instead of just updating the keys and config. I did this because I thought it could be a handy feature . For example, say you had a suspicion that one of your keys had been compromised and someone was using it to access your GitHub account — all you would have to do to stop the person would be to run the update command, hit enter a few times, and the compromised keys would no longer exist locally or on GitHub, and new keys would be created.
Lastly, I needed a way of deleting configs that were no longer in use. This works in a similar way to the other config commands:
jarvis config-delete git
When you run this command, Jarvis will ask you which config you would like to delete, and then delete it. This is as simple as deleting the config locally, removing the public SSH key from GitHub, and deleting the SSH keys and config locally. If the config being deleted was the active config, then Jarvis will also ask you to activate a new config.
The GCP config commands work in basically the same way as the git ones. The only real difference between them is instead of creating, updating, and deleting SSH keys, Jarvis creates, updates, and deletes gcloud configs. I knew this wouldn’t be too difficult to implement because, as a long time user of the gcloud CLI I knew that I could do all of the above using the
gcloud config configurations create/delete/activate and
gcloud config set commands.
The only problem I had to overcome was with the delete command — you can’t delete an active gcloud config. I solved this by creating a gcloud config called jarvis-dummy that Jarvis could activate before deleting a config. This way, even if you use Jarvis to delete every GCP config that you have created, it will always complete.
The S3 config management was the simplest of the three to build. This is because I didn’t have to communicate with or manage anything on any external platforms. S3 configs only needed to be stored locally because all interaction with S3 would be done through the aws-sdk package, so all I needed was to be able to read values from the stored configs.
And with that, the config management part of Jarvis was complete…well, sort of. I also decided it would be useful to have a way of quickly viewing all the stored configs. This was as simple as reading the stored configs and printing them out when the following command is run:
jarvis config-view git|gcp|s3|all
Working With Git
The git config management was the last of the three that I built, so I decided to keep the git train moving and build the rest of the git functionality. I knew from my requirements that I would need four commands:
jarvis git-push <version>
jarvis git-clone <repoName>
Let’s start with
git-init. I wanted this command to make the initialisation of a git directory simpler. The first thing it needed to do was run
git init, and it also needed to run
git remote add origin to add the remote origin. I decided that it would also be a good idea to have this command activate a git config, that way running one command would have you completely set up to start using other git commands.
git-pull are both commands that do exactly what you would think. I wanted to add them to Jarvis mainly because it’s a pain typing out the full git command. So for example, instead of:
git pull email@example.com:username/repoName.git
You would type:
jarvis git-clone repoName
These work by reading the active stored git config and using the data from that to format the git command. The only extra thing that they do is check that the active git config is correct before executing the git commands.
git-push <version>, this command was born in a similar way to pull and clone. Why type out three commands when you can type one? For example:
jarvis git-push 1.0.0
git add -A
git commit -m "1.0.0"
git push -u origin master
Just like pull and clone, push also checks to see if the active git config is correct before executing anything. When running the
git add command, Jarvis will by default add all files with changes. You can also pass in the files that you want to add, for example:
jarvis git-push 1.0.0 file.js
jarvis git-push 1.0.0 file1.js file2.js
The React commands have so far been the biggest time saver for me. Let’s start with:
jarvis react-init <projectName>
With this command, you can have a basic react project set up in minutes, instead of taking half an hour to get everything set up. Init starts by initialising a git directory using Jarvis’s inbuilt git init command. Once git has been initialised, it starts creating all the files and folders in the following structure:
I tried to create as basic and standard a structure as possible, so it is useful to as many developers as possible — but of course, everyone has their own preferences on project structure. I want to keep improving this structure based on your input, so that it becomes more useful. All the files are populated with boilerplate content that allows tests to be run, webpack to work, and a basic website with home and 404 pages to be served.
It doesn’t stop there though, once all of the files and folders are created Jarvis will then run npm install and wait for all of the packages to finish installing. It will then ask if you want to run
npm run test and will run them if you tell it to. I added this to the command so that you can make sure all the files have been created correctly — if they have the tests will pass. After the tests have finished running, Jarvis will then ask if you want to build and run the project, if you answer yes then it will run
npm run build and webpack will build the files and serve them.
react-init allows you to completely set up a basic react project in a couple of minutes and get straight into building cool things.
react-create command exists for the same reason as the
git-push command — why type out a load of commands when you could type one? In this case it’s:
jarvis react-create ComponentName
This command has the added benefit of populating the files with boilerplate contents to get the component working straight out of the box.
I mentioned in my requirements that I wanted a command that deploys a react app to Google App Engine, pushes the changes to GitHub, and uploads the static files to S3 all in one,
react-deploy <version> is the command that does this.
This command first runs the tests to make sure that everything is working. If the tests fail, the command will fail. If the tests pass, then it moves on, using webpack to do a production build. This creates a few files, mainly
index.js.gz. Just like with the tests, if webpack fails to build the app, the command will fail. Next, we push the changes to GitHub, using Jarvis’s
Once the new version has been pushed to GitHub, Jarvis gets on with actually deploying the app to Google App Engine. The gcloud CLI made this nice and simple to implement by using the
gcloud app deploy command. Currently, this command only deploys to GAE, because this is what I have to deploy to 99% of the time. I do have plans to add more platforms to this command in the future, but this is low on the priority list so I left it out of this version.
Lastly, Jarvis uses the aws-sdk package to upload the css and js files that webpack created to S3. Once these files have been uploaded, the app is now deployed and ready to be used on the world wide web. Before each step is executed, Jarvis checks that the active config is correct to make sure that everything ends up where it needs to be.
Opening and Searching Websites
The last feature that I added was the ability to open and search websites quickly. If like me you always have the command line open when developing, you will probably find this feature as useful as I have. The only downside to this feature is that it is macOS specific. It works by using the
open command with the browser name and URL as arguments. So instead of moving away from your command line, opening your browser, typing in the URL, and hitting enter, you can now do:
jarvis site-open <site>
Jarvis will do it all for you. The site argument can be two different things, it can either be the full URL of the website, or you can type one of Jarvis’s predefined shorthand site identifiers. Currently, the following id’s are available for
jarvis site-open so (Stack Overflow)
jarvis site-open npm (NPM)
jarvis site-open cocoa (CocoaPods)
jarvis site-open g (Google)
jarvis site-open awe (Awesome)
jarvis site-open gh (GitHub)
If you want to go straight to searching for something on a website, you can do that by using the
site-search command. When this command is run, Jarvis will ask what you want to search for before executing the command. With this command you can’t just pass in any URL, you have to use a predefined shorthand. The available shorthands are:
jarvis site-search so (Stack Overflow)
jarvis site-search npm (NPM)
jarvis site-search g (Google)
jarvis site-search gh (GitHub)
Once you have entered what you want to search, Jarvis will open a Chrome tab with the search results. This command has sped up my workflow more than I thought it would and I now use it all the time.
Jarvis is something that I will keep working on, I have some big plans for the future, some of which I have mentioned in this piece. I’ve also uploaded Jarvis to GitHub and NPM so that anyone can use him and contribute to his abilities. One of my aims with Jarvis was to build something that can have an awesome community behind it, with everyone sharing their ideas and needs so that Jarvis can help as many people in their day to day work as possible.
If you want to install Jarvis, you can either clone it from GitHub:
git clone https://github.com/willptswan/jarvis.git
Or install it using NPM:
npm install -g @willptswan/jarvis
You can check that Jarvis has installed correctly by running
I hope that you have enjoyed reading about why and how Jarvis came to exist as much as I enjoyed building him and writing this story. I am looking forward to Jarvis’s future and seeing a community grow around him.