Published: 24.08.2020 | Edited: 22.12.2020 | Tags: bash,git
How to update Google Calendar with pre-push git hook
With my online course building journey, I had to keep track of the slides it has. My coach has set me goal and it looked like a really hard one to reach, but it seemed doable. I wanted it to be a challenge. By some numbers I got from the previous month, I came up to the conclusion that I can build on average around three slides per day. I was quite comfortable with that number but coach though different.
Make it four.
This was his words. He personally went similar journey before me and he knew how to push himself. Being a coach, he also knows how to push others that need help. Jumping from three to four slides a day does not seem like a lot but it meant increase from 90 to 120 slides. Doing 4 slides a day, I would be finished in around 23 days, which would leave me with exactly 7 days for other projects and relax. Now all 30 days of the upcoming month were already occupied in my calendar.
I am bulding the slides by using pandoc. Pandoc is a great piece of software that allows me to transform markdown text into revealJS presentation. Which is just another great tool and if you do not know about these, just take a look. They both contain more features than I could count.
One of the concepts that RevealJS provides which is not common among other presentation engines I have tried (PowerPoint, LibreOffice Impress or LaTeX Beamer) is that it provides two-dimensional slide arrangement. It makes a grid with vertical and horizontal slides. All of the former have only one dimension, or at least it held true up until time I had tried them without much special configuration.
Markdowns level 1 heading (denoted by a single hashtag
#) get's converted to a horizontal slide. You can thing of a horizontal slide as a chapter name. It denotes a part of the presentation, but does not bear any content to itself. All level 2 headings (denoted by double hashtag
##) get converted by a vertical slide below the current horizontal one, up to the next vertical one. Only vertical slides show content (text, bullet lists, images, ...). It feels really logical and neat to me. As a side bonus, when you press
o key, it displays you a whole 2D outline of your presentation, which looks like a grid.
Since a whole course is a one gigantic
.md file, which of course is stored as a text format, we can simply count all level 2 headings in that file to get a number of slides programatically. Syntax is the same for
# the_silver_searcher ag "##" presentation.md | wc -l # grep grep "##" presentation.md | wc -l
If you do not use the_silver_searcher, it is also one of the tools worth looking into. It claims to be much faster than grep. It can save you a few miliseconds here and there. As a side note,
ag is only two characters, which is half compared to
grep. Unless you have an alias that looks something like
alias gr='grep', it laso saves you keystrokes.
The result displays a single number that shows the count of lines containing level 2 markdown heading, which represents number of horizontal slides in the presentation. Since only horizontal slides have a content, this is precisely all we need.
Google Calendar API
At first, I ust thought updating an event in a gCal would be really fast, but I could not be further from the truth. The HTTP API documentation for PATCH method shows tidy URL. PATCH is the method usually used in REST API to update part of the entity.
Yeah, nice! I just run a
curl or it's newer cousin, httpie request to update some information in the Google calendar event and I am done. Well, it requires three additional pieces of information:
I had tried looking at URL browsing gCal web UI, but I could not find any IDs there, nor anywhere in the settings. The authorization part was even more complicated. If you have never enabled a Calendar API, it is a lot of steps. I will not explain them here, because they are docuemnted by the Google itself, and as anything Google, they are suject to (frequent) change. What I ended up doing was enabling it and not used
curl, nor any other plain request tool, because handling OAuth2 access and refresh tokens in bash would be a hassle. There is also an older API key based way, which could work easily, but it has some limitations and it was not completely clear to me, if it is still a feasible option, thus I went with OAuth2 option.
The update script
Google Calendar API also supports multiple languages (more are being added):
My course is made as a node.js project, so naturally I have followed the provided quickstart [example](https://developers.google.com/calenda r/quickstart/nodejs). Unfortunately, it only shows how to create an event, not how to update the existing one. I have tried learning more about the node API for Calendar
patch method here but somehow, I could not understand a word there. Again, StackOverflow for the help. The post here shows the guidelins to updating the event. By combining these three resorces I was able to get a working script, you can have a look at the source.
Bash in node
If you dig through the script, you might find one another oddity: function
lineCount. It calls a bash command we have found earlier in a node script. I could do it straight up in the node, so it would not be such a tangled mess, but hey, I had it already figured out and life is short.
Following a Medium article provided not one but multiple already working options to do this. I have chosen the one that uses promises. Even though the quickstart article used callbacks, I wanted to progressively evolve the script to only use arrow functions and
async/await syntax in the end, if possible.
Git hook is a technique to call certain scripts during a git lifecycle. There is a lot of them. You can learn more by studying sample files
ls .git/hooks/*.sample in your repository or by
man githooks. Since there is a lot of them, choosing the right one can be difficult. Initially I have thought that I use
post-push, but as I have later learned, such a hook does not exist in git! The StackOverflow's post was first thing that popped up in the search results, explaining that this hook would require the remote repository to execute the code, which is not implemented.
The next thing in line was
pre-push hook. Usually, pre-hooks are used to perform checks before executing an action (for example checking for wording in commit mesage). I did not need perform any checks to be performed, I just wanted to call a script together with the
git push. This time, it did not matter if it was performed before or after the push, so I used it.
One another question was where to put hooks to be tracked by git. Putting hooks inside
.git/hooks/ directory makes them work, but git wont list them as untracked files. If a hook is part of the overal project, you have to put them elsewhere. This Medium article outlines a concept to put tehme inside
hooks/ directory and symlink them to
mkdir hooks cd hooks touch pre-push cd .. # CAUTION: the -f parameter overwrites destination ln -s -f ../../hooks/pre-push ./git/hooks/pre-push
By setting this working script as a
pre-push git hook, I was able to update my Google Calendar event automatically together with
git push. Now the advantages are threefold:
- I can see the slides count straight up
- My couch can track my progress
- My girlfriend can see if I am meeting my goals or if I need more help
The third one is especially helpful, if you have a commited, helpful girlfriend like I do. It helps us plan out relax time much better this way.
Hopefully, this guide was helpful to you in some way, be it general knowledge, task automation, git concepts or you are just curious. If you have any questions, please contact me.