Notion for task management (with Github integration)

Heritage Holdings Tech Blog
7 min readFeb 14, 2023

--

Welcome to our guide on streamlining task management with Notion and Github integration. In this article, we’ll be diving into our team’s approach to combining these two powerful tools. Whether you’re new to using Notion or a seasoned pro, this guide will provide valuable insights and tips for optimizing your workflow. So, let’s get started!

Requirements:

  • Notion as the company’s space for product management
  • Code repositories hosted on GitHub

The code and process described in the following paragraphs are already available as a Danger JS plugin at this link. You can freely use it in your project following the instruction in the README!

Let’s use Notion

As you probably know, Notion is growing as one of the best “all-in-one” tools in the market. You have close to all the functionalities of task manager, note taker, and project management tools in one single place, right at arm’s length. Combine this with a never-ending stream of new features plus a really strong community and you have software that can handle almost all aspects of your business.

In Heritage, we decided to use Notion as our main project management space for two main goals:

  1. Having a central knowledge base with structured and unstructured notes
  2. Keeping track of tasks across multiple projects

While we understand that creating and maintaining global documentation is crucial, we’ll save those discussions for future articles to fully explore the task management space, the second point of our list.

The Notion logo.

Building projects on Notion

Project management tools are intricate systems that cover a wide range of aspects related to overseeing projects, such as task organization, scheduling, and resource allocation. To not make confusion, let’s define what we mean by “Task” before diving into the article:

A Task is an atomic and self-contained piece of work that needs to be handled by a Person. It must be related to a specific Project, be of a particular Kind (E.g. feature, chore, …) and can contain one or more related sub-tasks.

From this simple definition, we identify five main variables of a Task:

  • The Content (or Description) of the Task
  • The Person who is in charge of the Task
  • The Reporter who ensures the task gets implemented
  • The Kind (or Type) of the Task
  • The Relations of the Task (a Task must be related to a specific Project and could have multiple sub-tasks)

After some research, we realized that Notion’s Database was the right tool for our needs. In Notion, a Database is a structured way to handle pages, with the ability to add custom information and establish relationships among them. By defining a Task as a simple Notion page and incorporating all necessary parameters, we are already halfway.

This screenshot showcases various Notion’s features, such as Project, Type, and Assigned fields. The Status field is another unique feature of Notion that allows for the calculation of the percentage of completion (Completed field) using a Rollup.

The concept of Sub-Tasks may seem a bit more complex. The Parent field describes the relation to a higher task in the hierarchical structure. This means that all top-level tasks have an empty Parent field, while a Sub-Task is simply a Task with a Parent field linked to… well, its parent! To reduce clutter, the Kanban-like board will only display top-level tasks, with a list of all related Sub-Tasks displayed within each task.

The task lifecycle

To move forward with our framework, it’s important to distinguish the 4 steps in the lifecycle of a task:

  1. Not started: The task is in the backlog and is not being handled by anyone
  2. In progress: The task is currently being developed and, if the Pull Request property is filled, there is a Pull Request on GitHub ready to be reviewed or discussed
  3. Done: The Pull Request on GitHub has been approved (merged and closed) and it's considered "valid" from a technical perspective. The task has likely been merged into the main source code, but it's possible that something unexpected happened and the Pull Request is just closed
  4. Accepted: After the task and the PR has been reviewed for a further time(s), it will be manually moved to this final stage

Integrating with GitHub

In the images above, you may have noticed a field called Pull Request. This field holds a link to the corresponding GitHub Pull Request that ultimately resolves the task. But the integration between our Notion database and GitHub is a bit more magical than just a simple link. Our magic wand is Danger Bot, which runs a script at every PR update (title, status, or description). At the moment, the bot can:

  1. Scan through the PR’s content searching for the classic GitHub linking words (closes, fixes,…) followed by the Notion URL(s) to Tasks in Notion
  2. Update the linked Tasks’ status based on the PR’s status. For example, when a PR is opened, the linked Task will be moved to “In progress” and when it’s closed/merged, the Task will be moved to “Done
  3. Add the PR link to the relative field in the Task
  4. Comment the PR with a list of the linked Tasks in Notion.

An example workflow

Here’s an example of how we might use our Notion set up to handle a task such as increasing the size of our company logo:

  1. A PM or developer creates a new task “Increase the Heritage logo size” in the Notion backlog
  2. The developer creates a pull request (PR) on GitHub and includes the sentence This PR fixes [task link here] in the PR’s description
  3. Opening the PR triggers the Danger Bot to scan the PR’s description, find the linked Notion tasks, and move them to the “In progress” status. The bot also adds the PR link to the Pull Request field on the task.
  4. After the PR is reviewed and merged into the main source code, the Danger Bot moves the Notion task to the “Done” status.
A diagram of the flow descripted above.

The code

To link a Task to a PR, we are using the standard GitHub keywords. This means that not every Notion link will be recognized, but only those that match the following Regex:

/(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\s+(https:\\/\\/www\\.notion\\.so\\/heritageholdings\\/[^\\s]+-\\w+)/gi;

To update the corresponding Notion Task, we extract the unique page ID from the link included in the PR and utilize the Notion JavaScript SDK to add information to the task’s properties.

/**
* Update a single Notion task using the current
* PR to compute the various properties. This function
* will also return all the details of the same task.
*/
const updateNotionTask = (
taskId: string,
pr: {
status: __dm.GitHubPRDSL["state"];
url: string;
}
) => {
console.log("Updating Notion task", taskId);

// The generateTaskStatus(status: string): string function will
// just map the PR status to the relative Task status in Notion.
const taskStatus = generateTaskStatus(pr.status);

return notion.pages.update({
page_id: taskId,
properties: {
Status: { status: { name: taskStatus } },
"Pull Request": { url: pr.url }
}
});
};

When a Task is identified in the PR, it is passed through this function to perform the necessary updates on Notion. Then, the notion.pages.update method returns all the details of the page in Notion including the Task title which is then added as a comment on the GitHub PR:

// Create a list of tasks to add inside the Danger comment.
// Here `successfulTasks` is just the list of Notion Tasks handled
// by the script with all the needed details.
const tasksListStr = successfulTasks.reduce(
(acc, next) => acc + `- [${next.title}](${next.url})` + "\\n",
""
);

markdown(
(successfulTasks.length > 1
? `## 🗂 ${successfulTasks.length} Notion tasks found`
: "## 🗂 Notion task found") +
"\\n" +
tasksListStr
);

Resulting in:

What’s next

We are committed to continuously working to improve our integration between Notion and GitHub, keeping up-to-date with the latest developments from Notion to optimize our workflow. Future developments may include:

  • Instructing the code to handle closed PRs, moving related tasks to the appropriate stage of the task lifecycle when the corresponding PR is closed.
  • Integrating the system with Slack to send notifications to creators and reviewers (if you are interested in Slack-Github integration, read also How to create a bot for code reporting activities)

With this Notion-GitHub integration in place, our team can streamline the process of task management and collaboration. By utilizing the power of Danger Bot, we can automatically update the status of tasks and provide clear and concise information about progress to all stakeholders. As we continue to improve and refine this integration, we can ensure that everyone is on the same page, resulting in a more efficient and effective way of working together toward our team’s goals.

Written by Diego Pasquali and HTECH Team

A diagram with a hearth linking Notion and GitHub.

--

--

Heritage Holdings Tech Blog

Heritage is a private investment platform built by families for families. Our blog shares engineering challenges, culture, values, best practices, and more.