Self-updating GitHub Profile README with JavaScript
Tags: github, javascript, git, markdown
Published: 2020-08-04 21:38:26

GitHub recently released a feature that allows users to add markdown to their profile. People have done [some pretty cool things](https://dev.to/github/10-standout-github-profile-readmes-h2o), which inspired me to create a README that dynamically updates with my Dev.to posts. [Here's the link to my GitHub repo](https://github.com/danielcurtis/danielcurtis), which has a live example!

GitHub Actions and NodeJS make this easy. I created a script to:

1. Get my Dev.to articles
2. Parse my README
3. Update the README with my latest articles

GitHub Actions make it possible to schedule automatic runs of a program at timed intervals, known as a [cron job.](https://en.wikipedia.org/wiki/Cron#:~:text=The%20software%20utility%20cron%20is,times%2C%20dates%2C%20or%20intervals.&text=Cron%20is%20most%20suitable%20for%20scheduling%20repetitive%20tasks) 

I currently have my GitHub Action Workflow configured to run the script three times a week. I thought this would push me to publish articles three times a week, but that hasn't happened yet...

You'll need 3 files: `.github/workflows/build.yaml`, `updateReadme.js`, and `README.md`. Without further ado, here's the code:

**.github/workflows/build.yaml**

```yaml
# Name of workflow
name: Build README

# Run workflow at 12:01 on Sunday, Wednesday, and Friday
on:
  schedule:
    - cron: '1 12 * * 0,3,5'
  # Run workflow on pushes to main branch
  push:
    branches:
      - main

# Steps to carry out
jobs:
  build:
    # Create a ubuntu virtual machine
    runs-on: ubuntu-latest
    
    # Checkout repo code
    steps:
    - name: Checkout repo
      uses: actions/checkout@v2
    
    # Install node
    - name: Use Node.js
      uses: actions/setup-node@v1
      with:
        node-version: 10.16
    - run: npm install
    - run: npm run build --if-present
    - run: npm test
      env:
        CI: true

    # Run script "updateReadme.js" 
    - name: Update README
      run: |-
        node updateReadme.js
        cat README.md

    # Commit changes
    - name: Commit and push if changed
      run: |-
        git diff
        git config --global user.email "readme-bot@example.com"
        git config --global user.name "README-bot"
        git add -A
        git commit -m "Updated articles" || exit 0
        git push
```

**updateReadme.js**

```js
// Include node fs (file stream) and https modules
const fs = require('fs');
const https = require('https');

// API endpoint
const url = 'https://dev.to/api/articles?username=<YOUR DEV USERNAME>';

function readWriteAsync() {
  // Get articles using HTTPS
  https.get(url, (res) => {
    res.setEncoding('utf8');

    // Set variable body to response data from API
    let body = '';
    res.on('data', (data) => body += data);

    res.on('end', () => {
      // Parse the JSON response
      body = JSON.parse(body);

      // Shorten array to latest 3 articles
      body = body.slice(0, 3);

      // Create string of markdown to be inserted
      const articles = `\n - [${body[0].title}](${body[0].url})\n - [${body[1].title}](${body[1].url})\n - [${body[2].title}](${body[2].url})\n \n`;

      // Update README using FS
      fs.readFile('README.md', 'utf-8', (err, data) => {
        if (err) {
          throw err;
        }

        // Replace text using regex: "I'm writing: ...replace... ![Build"
        // Regex101.com is a lifesaver!
        const updatedMd = data.replace(
          /(?<=I'm writing:\n)[\s\S]*(?=\!\[Build)/gim,
          articles
        );
        
        // Write the new README
        fs.writeFile('README.md', updatedMd, 'utf-8', (err) => {
          if (err) { 
            throw err;
          }

          console.log('README update complete.');
        });
      });
    });
  });
}

// Call the function
readWriteAsync();
```

**README.md**

```md
# Self-updating README

This text won't be change.

The text below will be, though!

What I'm writing:

- This will be replaced
- This too!
- This three!

![Build README](https://github.com/<YOUR GITHUB USERNAME>/<YOUR GITHUB USERNAME>/workflows/Build%20README/badge.svg)

This won't be impacted either. The text above is a GitHub build badge.
```

I tried to explain what the code is doing with comments, which makes the code look longer/more daunting than it is. [GitHub Action's documentation](https://docs.github.com/en/actions) and [this README cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) are excellent if you're just getting started with either. [Here's another link to my GitHub repo](https://github.com/danielcurtis/danielcurtis), to see it live!

What are your README tips for this new feature? 👀