DEV Community

Cover image for Highlighting: sync-contribution-graph
Matthew Foley
Matthew Foley

Posted on

Highlighting: sync-contribution-graph

A couple of weeks ago, I nearly scrolled past this gem on my twitter feed: sync-contribution-graph, by @kefimochi. Go have a look!

You can use this tool to have your GitHub contribution graph accurately reflect contributions from other accounts you make use of. For example, outside of work I use the handle mtfoley, but I have a separate account I use for my job. I like the idea that I could use this to accurately reflect my activity level, and that no private information about that work handle is revealed.

The way it works is pretty straightforward. When you configure it with a username and a time frame (year), it performs an HTTP request to the appropriate URL, and parses the HTML in the response for the dates/counts of contributions (these correspond to those little green squares). Based on this data, it creates appropriate git shell commands. The shell commands are saved to a file that can optionally be run immediately. Here's a snippet that's the meat of it in src/index.js:

import { parse } from "node-html-parser";
import axios from "axios";
import fs from "fs";
import shell from "shelljs";


// Gathers needed git commands for bash to execute per provided contribution data.
const getCommand = (contribution) => {
  return `GIT_AUTHOR_DATE=${contribution.date}T12:00:00 GIT_COMMITER_DATE=${contribution.date}T12:00:00 git commit --allow-empty -m "Rewriting History!" > /dev/null\n`.repeat(
    contribution.count
  );
};


export default async (input) => {
  // Returns contribution graph html for a full selected year.
  const res = await axios.get(
    `https://github.com/users/${input.username}/contributions?tab=overview&from=${input.year}-12-01&to=${input.year}-12-31`
  );


  // Retrieves needed data from the html, loops over green squares with 1+ contributions,
  // and produces a multi-line string that can be run as a bash command.
  const script = parse(res.data)
    .querySelectorAll("[data-count]")
    .map((el) => {
      return {
        date: el.attributes["data-date"],
        count: parseInt(el.attributes["data-count"]),
      };
    })
    .filter((contribution) => contribution.count > 0)
    .map((contribution) => getCommand(contribution))
    .join("")
    .concat("git pull origin main\n", "git push -f origin main");


  fs.writeFile("script.sh", script, () => {
    console.log("\nFile was created successfully.");


    if (input.execute) {
      console.log("This might take a moment!\n");
      shell.exec("sh ./script.sh");
    }
  });
};
Enter fullscreen mode Exit fullscreen mode

I made some suggestions in the setup workflow on the repo and submitted a PR to update the README. I hope you find this and other work by @kefimochi to be of interest!

Top comments (0)