I live on Hashnode and Github now. So I thought, how can I show my Hashnode contributions on my Github Profile Readme?
Note: This post is a little intense if you are a Git beginner but source code to all of this tutorial is linked to the bottom of this post! Even if you are new, give it a read and see if you can learn something out of it. Cheers!
If you write on Hashnode want to make your Github Profile lively like I did, then this post is 100% for you. Here is what I managed to do using the Hashnode API and Github actions. I made my Readme automatically fetch my most recent posts from Hashnode and it auto updates every few hours.
What exactly do I need to do?
Well the GitHub Profile Readme basically is simply the Readme.md file that you make in a repository on GitHub which has name as your username on github. So basically it is a repository at
https://github.com/[username][username]
. You can read more about that here .And this Readme will show up on
https://github.com/[uername]
. So if we want to make sure that this file has our Hashnode posts, we could either update them ourselves every now and then.
But we like to automate around here.
To automate contents of a Readme we need to use Github Actions. Actions are simple instructions that we can run within Github for each repository on a timely basis or in response to certain events(push, pull, commit, pull-request or external events etc).
A GitHub Action that I use
Long ago when Github Actions were first opened to public, I created an action to update the contents of my Readme and it looked something like this.
Scary script ahead. But don't worry, you don't have to care about the code here too much. Just look at the names of each of the steps in my build
job.
name: README build
on:
push:
branches:
- master
schedule:
- cron: '0 */3 * * *'
repository_dispatch:
types: [deploy-github-readme]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v1
- name: setup node
uses: actions/setup-node@v1
with:
node-version: '13.x'
- name: cache
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.os }}-js-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
run: npm install
- name: Get top github contributions
id: top-github-contributions
uses: imbhargav5/actions/top-gh-contributions@master
with:
token: ${{ secrets.TOKEN }}
- name: Get Github summary
id: github-summary
uses: imbhargav5/actions/contentful-entry@master
with:
...
- name: Get recent blog posts from my older blog service
id: recent-blog-posts
uses: imbhargav5/actions/contentful-entries@master
with:
...
- name: Generate README file
run: node action.js
env:
TOP_CONTRIBUTIONS: ${{steps.top-github-contributions.outputs.top-contributions}}
NOTABLE_CONTRIBUTIONS: ${{steps.top-github-contributions.outputs.notable-contributions}}
GITHUB_SUMMARY: ${{steps.github-summary.outputs.entry}}
BLOG_POSTS: ${{steps.recent-blog-posts.outputs.entries}}
- name: Push new README.md
uses: mikeal/publish-to-github-action@master
env:
GITHUB_TOKEN: ${{ github.token }}
- I just try to get data from a bunch of services that I use
Codementor
where I teach code or some of my notable contributions on Github etc and then populate my readme using a simple Node.js script.
- I want to do something very similar with a custom Github Action for Hashnode pots and integrate into my workflow.
Understanding the Hashnode API
The most important step is to grab Hashnode
posts. Hashnode allows you to pull in a fair amount of public data using their api at api.hashnode.com.
So I tried checking if I can even fetch posts by username and the Hashnode guide was actually outdated on this one. So I dug into other GitHub actions (I ended up making my own action because the other action used it's own UI and I didn't want to give up control over the UI and wanted to make this usable for anyone who wanted just the posts without custom HTML.) with Hashnode links and found that I can run this query today and get the posts I need to show on my Readme.
{
user(username: "imbhargav5"){
name
username
numFollowers
publication{
posts{
title
coverImage
brief
}
}
}
}
So first I wrote a Node script to test out fetching the content using the GraphQL api.
const { gql, GraphQLClient } = require("graphql-request");
const client = new GraphQLClient("https://api.hashnode.com");
const query = gql`
query getUserPosts($username: String!) {
user(username: $username) {
name
username
photo
coverImage
numFollowers
numReactions
publicationDomain
publication {
posts {
title
coverImage
brief
cuid
bookmarkedIn
}
}
}
}
`;
async function getHashnodePosts(username) {
try {
const data = await client.request(query, { username });
return data;
} catch (err) {
console.log(err);
return {};
}
}
module.exports = getHashnodePosts;
I can now use this as Javascript Github Action and use it to populate my Readme.
I thought others would also find this useful. So I created a simple GitHub action that gave this output in the form a JSON and put it on the marketplace that anyone can use.
Check it out over here !
Using the action
The usage is pretty simple.
- First. Create a simple Node file in your repository like so. This Node script simply grabs hashnodeProfile from the env it runs in and can then create HTML content out of it.
//./main.js
const main = require("./main");
//...
const hashnodeProfile = JSON.parse(process.env.HASHNODE_PROFILE)
//...
function generateReadme(){
const username = `${hashnodeProfile.user.name}`
// Generate postsHTML too
const postsHTML = ''
return `
Hey. I am ${username}
${postsHTML}
`
}
generateReadme()
- Secondly, In the workflow to update Readme add this step to fetch your posts and also supply your username as input.
- name: Get recent blog posts from hashnode
id: hashnode-recent-blog-posts
uses: imbhargav5/hashnode-user-with-posts-json@master
with:
username: "imbhargav5"
- Finally, create a step to run the node script and add HASHNODE_PROFILE to its env like so.
- name: Generate README file
run: node action.js
env:
OTHER_STUFF: whatever
HASHNODE_PROFILE: ${{steps.hashnode-recent-blog-posts.outputs.data}}
- name: Push new README.md
uses: mikeal/publish-to-github-action@master
env:
GITHUB_TOKEN: ${{ github.token }}
Results time
Once I managed to get my Github Action and Node script to generate Readme sorted. I put them all together and now this is how my readme looks like.
The Hashnode posts are populated at the bottom right in a list format!
More details
I used Mustache.js to generate my HTML. It's pretty easy to use and comfortable so I used it, but you can use any tool that you look. End goal is to generate HTML and push to your repository.
You can read the entire source here .
Thanks for reading!!
Thanks and Please support my work
- Writing blog posts and making videos is an effort that takes many hours in my day. I do it because I love teaching and make great content.
- However, I need your support too. Please support my work and follow my social accounts to help me continue to make great content.
- Here are my social links.
Follow me on Twiter
Subscribe to my channel on Youtube
Thank you!