Setting new goals is easy, achieving them is hard.
I have used a variety of tools over the years to help me achieve my goals. I have used a combination of Google Docs, Google Calendar, Google Keep, Loop Habit Tracker, Trello, and good olâ alarm clocks to schedule tasks and remind myself to get things done. Whether these goals were personal or professional, small or big, they would usually find their way into one of these tools with the hope that it would hold me accountable.
When it came to my major goals (e.g. âdo real good in schoolâ, âget a jobâ), these tools were more organizational than motivational. If a goal is truly important to me, I donât struggle to find motivation. Conversely, I have set many goals that sit in a grey area of motivation. These goals are much more difficult for me to achieve because they are deemed ânot-so-importantâ or ânot completely necessaryâ, even though they are enjoyable and fulfilling activities. Unfortunately, their lack of priority means that they are often side-lined by major goals or leisurely activities.
Examples of these ânot-so-importantâ goals include:
- Read 12 books this year
- Go for a run 3 times per week
- Meditate for 10 minutes every day
If you have set goals like these in the past, you will know how easy it is to avoid them. These goals were particularly easy to ignore because the tools I was using were simple reminder engines. Reminders alone are useful, but only if you are motivated and organized at the very moment they arrive. If you are not, they have no real power. It is extremely easy to swipe away a push notification, especially when you are not in the mood for it. So for the last 6 months, I have been experimenting with a tool that has radically changed my mindset around these types of goals. That tool is Beeminder.
âItâs reminders with a sting!â
The simplified premise of Beeminder is as follows:
- Set a goal
- Create a commitment contract (e.g. âI will run 3 times per weekâ)
- Input your data (manually or automatically via app integrations)
- Stay on track or Beeminder charges your credit card
In my experience, when I introduce Beeminder to people for the first time they usually think one of two things:
- âWow, that sounds great!â
- âWow, that app would take all of my money.â
Fair enough. Beeminder is not for everyone. For me, Beeminder provided the missing piece of the puzzle for my lower priority goals. Knowing that I could lose money from neglecting my goals forced me to decide whether being lazy in the moment was truly worth it or if I should just do what I said I was going to do.
So I wholeheartedly endorse Beeminder for those who think this kind of motivational scheme would work for them. Itâs worked great for me, particularly with keeping up with my reading and exercise goals through lockdown. I have lost money ($25 USD at time of writing) for forgetting to read or not finding the time to exercise, but using Beeminder has been completely worth it.
Programming goals
Now, because Iâm a very sane person, Iâve taken to Beeminding other goals since my initial success with reading and exercising. Staying up-to-date with new technologies and programming skills is important for my career. So Beeminding my programming activity was a natural next step.
Beeminder provides an official integration with GitHub, called gitminder
, that left me slightly disappointed. The integration only supports data tracking in the following scenarios:
- Commits in a single repository
- Issues closed in a single repository
- Commits across your entire account
- Issues closed across your entire account
Having only these scenarios to choose from, Beeminder users are prevented from defining complex programming goals. For example, the configurations above are not flexible enough for a âLearn Pythonâ or âContribute to Open Sourceâ goal. These goals could span multiple repositories, but would likely not include every repository in my account. Conversely, what if I was learning python AND contributing to open source in a single repository? That scenario would require a single repository connected to multiple goals, which is not possible through gitminder
. Additionally, programming activity is not just restricted to commits and closed issues. There are many other events on GitHub (e.g. pull requests, opened issues, publishing releases, deployment), that could be used to contribute towards Beeminder goals.
So instead of giving in and manually tracking my programming goals, I built a tool that addresses all of the above concerns.
multigitminder
multigitminder
is a GitHub Action that helps users capture their programming activity as data for their Beeminder goals. This tool allows users to connect any number of GitHub repositories to any number of Beeminder goals based on any combination of events supported by GitHub Actions.
How it works
If you are not familiar with GitHub Actions, it as an automation framework built directly into GitHub. It allows you to automate software development tasks that you would otherwise do manually on GitHub. It is primarily used to help software developers maintain and organize their projects. The great thing about GitHub Actions is that it can be used to automate any task, not just maintenance or organizational tasks.
So without getting into anymore detail on GitHub Actions, the important thing to know is that multigitminder
is a GitHub Action that automatically captures and sends data to Beeminder based on your specifications.
After installation, GitHub Actions will run multigitminder
every time your chosen event (e.g. commit, closed issue, pull request) occurs in or to your repository. The action uses a simple python script (via pyminder
) to push datapoints to Beeminderâs API.
You can install multigitminder
on any repository you own by:
- Creating a
.yml
workflow file in a.github/workflows/
directory - Specifying your goal parameters in the workflow file
- Storing your Beeminder username and authorization token as secrets in your repo
A basic workflow file using multigitminder
would look like this:
name: multigitminder
on:
push:
branches: [ main ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
Â
After adding that workflow file, you can add your secrets to GitHub by going to their repository Settings > Secrets > New Repository Secret. You can retrieve your Beeminder Auth Token from the Apps & API tab in the Account Settings page.
After this is done, you will have a basic implementation of multigitminder
that triggers on pushes to the main branch of your repository. From here, you can change your workflow file to suit your programming goal(s).
Basic Workflows
Perhaps you want data points to be submitted with every push and closed issue:
name: multigitminder-push-issue-closed
on:
push:
branches: [ main ]
issues:
types: [ closed ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
Â
Or when pull requests are opened or closed:
name: multigitminder-pull-request
on:
pull_request:
types: [ opened, closed ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
id: multigitminder
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
Â
Again, multigitminder
can be configured to trigger on any combination of events supported by GitHub Actions. So feel free to experiment with what works best for your Beeminder goals.
Additional parameterization
Specific Commits
multigitminder
can also be configured with a conditional statement, so that only specific commits trigger the workflow.
name: multigitminder-specific-commits
on:
push:
branches: [ main ]
jobs:
multigitminder:
if: "contains(github.event.head_commit.message, '[multigitminder]')" ## THIS LINE HERE
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
Â
In this example, only commits with âmultigitminderâ in the commit message will trigger the workflow.
Commit Messages as Comments
Additionally, you can use the commit message as the comment for each data point so that you can cross-reference your commits across GitHub and Beeminder.
name: multigitminder-commit-message-comment
on:
push:
branches: [ main ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
COMMENT: ${{ github.event.head_commit.message }} ## THIS LINE HERE
Â
Language-based Goals
You can configure multigitminder
to trigger based on the languages in your repository, with the help of fabasoad/linguist-action. This configuration ensures that multigitminder
only triggers if at least one of your target languages are found in the repository code.
name: multigitminder-linguist
on:
push:
branches: [ main ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
# Checkout
- name: Checkout
uses: actions/checkout@v2
# linguist
- name: Linguist Action
uses: fabasoad/linguist-action@v1.0.2
id: linguist
with:
path: './'
percentage: true
# multigitminder
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
id: multigitminder
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: YOUR_GOAL_NAME_HERE
TARGET_LANGS: YOUR_TARGET_LANGUAGES_HERE ## e.g. "['python', 'javascript']"
REPO_LANGS: ${{ steps.linguist.outputs.data }}
Â
One repository to multiple goals
Lastly, what if you want activity in a repository to contribute to multiple Beeminder goals? You can achieve this by creating a workflow file for each goal, changing the input parameters accordingly. For example, I want closed issues in my repository to contribute towards a âmaintenanceâ Beeminder goalâŚ
name: multigitminder-issue-closed
on:
issues:
types: [ closed ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: maintenance
Â
and pushes to the main and development branches to contribute towards a âwrite-pythonâ goal (provided python is found in the repo)âŚ
name: multigitminder-linguist
on:
push:
branches: [ main, dev ]
jobs:
multigitminder:
runs-on: ubuntu-latest
name: multigitminder
steps:
# Checkout
- name: Checkout
uses: actions/checkout@v2
# linguist
- name: Linguist Action
uses: fabasoad/linguist-action@v1.0.2
id: linguist
with:
path: './'
percentage: true
# multigitminder
- name: multigitminder
uses: HaydenMacDonald/multigitminder@v1.0.0
id: multigitminder
with:
USERNAME: ${{ secrets.BEEMINDER_USERNAME }}
AUTH_TOKEN: ${{ secrets.BEEMINDER_AUTH_TOKEN }}
GOAL: write-python
TARGET_LANGS: python
REPO_LANGS: ${{ steps.linguist.outputs.data }}
Â
With both of these workflow files in my ./github/workflows
directory, they will trigger independently of one another, according to their specifications.
Conclusion
If this project interests you, please experiment with multigitminder
! Check out the action on GitHub Marketplace or its home repository for more information.
I hope this tools opens the doors for modular programming goals in Beeminder. At least until the official GitHub integration becomes more flexible đ
Help
If you find a bug or have an idea on how to improve multigitminder
, please submit an issue on GitHub or send me an email at hmd[at]needleinthehay.ca.