{"componentChunkName":"component---src-templates-blog-post-js","path":"/gitlab-todos-hammerspoon/","result":{"data":{"site":{"siteMetadata":{"title":"Undefined","author":"Anirudh Varma"}},"markdownRemark":{"id":"0ed9b07f-d4a4-5a6b-b04d-da73daeda0fe","excerpt":"At SpotDraft we use self-hosted GitLab to host our source code and manage projects. One nice concept that GitLab uses is that of Todos. A Todo is created…","html":"<p>At <a href=\"https://spotdraft.com\">SpotDraft</a> we use self-hosted <a href=\"https://gitlab.com\">GitLab</a> to host our source code and manage projects. One nice concept that GitLab uses is that of <strong>Todos</strong>. A Todo is created anytime an issue is assigned to you, a Merge Request requires your review or someone mentions you in a comment, hence the Todos page serves as a hub for you to figure out what you can help with or what you can work on next.</p>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/118b73834ab7353d4cddeb77bc4d72d5/e9d87/gitlab-todo-menubar.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 4.0540540540540535%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAVklEQVQI1wXBQQtAMACAUf9FuSgKE4qx1dQoUYvJQY5O/v/l814go5DHGi7V49XAUlWYJGXKCm5jcaLBZy13rvnMzpkoDjGydTOrdZS1Ji4kzXhh3csPlrIkM+j+Z70AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"Gitlab Todo Menu\"\n        title=\"\"\n        src=\"/static/118b73834ab7353d4cddeb77bc4d72d5/fcda8/gitlab-todo-menubar.png\"\n        srcset=\"/static/118b73834ab7353d4cddeb77bc4d72d5/12f09/gitlab-todo-menubar.png 148w,\n/static/118b73834ab7353d4cddeb77bc4d72d5/e4a3f/gitlab-todo-menubar.png 295w,\n/static/118b73834ab7353d4cddeb77bc4d72d5/fcda8/gitlab-todo-menubar.png 590w,\n/static/118b73834ab7353d4cddeb77bc4d72d5/efc66/gitlab-todo-menubar.png 885w,\n/static/118b73834ab7353d4cddeb77bc4d72d5/e9d87/gitlab-todo-menubar.png 1176w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<p>So, to keep on top of my todos, without having to open GitLab all the time, I created a little <a href=\"https://www.hammerspoon.org/\">Hammerspoon</a> script that simply keeps the count of todos in my MacOS menu bar. For those who are not familiar with Hammerspoon, it is a MacOS automation that makes it super easy to interact with the operating system using a Lua Scripting Engine.</p>\n<h2 id=\"the-code\" style=\"position:relative;\"><a href=\"#the-code\" aria-label=\"the code permalink\" class=\"anchor-hint before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Code</h2>\n<p>I have never written a single line of Lua in my life before, but even then thanks to great documentation by Hammerspoon and the set of extensions already available, it did not take long to make this functional <em>“app”</em></p>\n<p>After installing Hammerspoon, open your <code class=\"language-text\">init.lua</code> file and add the following</p>\n<div class=\"gatsby-highlight\" data-language=\"lua\"><pre class=\"language-lua\"><code class=\"language-lua\"><span class=\"token comment\">-- URL to open when the menu bar is clicked</span>\n<span class=\"token keyword\">local</span> MENUBAR_CLICK_URL <span class=\"token operator\">=</span> <span class=\"token string\">\"https://gitlab.com/dashboard/todos\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">-- GitLab access token to make the API call</span>\n<span class=\"token keyword\">local</span> GITLAB_TOKEN <span class=\"token operator\">=</span> <span class=\"token string\">\"&lt;Your Token>\"</span>\n<span class=\"token comment\">-- TODOs API URL</span>\n<span class=\"token keyword\">local</span> GITLAB_TODO_API <span class=\"token operator\">=</span> <span class=\"token string\">\"https://gitlab.com/api/v4/todos\"</span>\n<span class=\"token keyword\">local</span> POLL_INTERVAL_MINUTES <span class=\"token operator\">=</span> <span class=\"token number\">15</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">onMenuClick</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    hs<span class=\"token punctuation\">.</span>urlevent<span class=\"token punctuation\">.</span><span class=\"token function\">openURL</span><span class=\"token punctuation\">(</span>MENUBAR_CLICK_URL<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">end</span>\n\ngl_menu <span class=\"token operator\">=</span> hs<span class=\"token punctuation\">.</span>menubar<span class=\"token punctuation\">.</span><span class=\"token function\">new</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\ngl_menu<span class=\"token punctuation\">:</span><span class=\"token function\">setClickCallback</span><span class=\"token punctuation\">(</span>onMenuClick<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">updateMenuBar</span><span class=\"token punctuation\">(</span>todos<span class=\"token punctuation\">)</span>\n    counter <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">for</span> index <span class=\"token keyword\">in</span> <span class=\"token function\">pairs</span><span class=\"token punctuation\">(</span>todos<span class=\"token punctuation\">)</span> <span class=\"token keyword\">do</span>\n        counter <span class=\"token operator\">=</span> counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">end</span>\n    gl_menu<span class=\"token punctuation\">:</span><span class=\"token function\">setTitle</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Gitlab Todos - \"</span><span class=\"token operator\">..</span>counter<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">end</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">callGitLab</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    headers <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"PRIVATE-TOKEN\"</span><span class=\"token punctuation\">]</span><span class=\"token operator\">=</span>GITLAB_TOKEN\n    gl_menu<span class=\"token punctuation\">:</span><span class=\"token function\">setTitle</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Fetching Todos...\"</span><span class=\"token punctuation\">)</span>\n    hs<span class=\"token punctuation\">.</span>http<span class=\"token punctuation\">.</span><span class=\"token function\">asyncGet</span><span class=\"token punctuation\">(</span>GITLAB_TODO_API<span class=\"token punctuation\">,</span> headers<span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>status<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n        todos <span class=\"token operator\">=</span> hs<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">.</span><span class=\"token function\">decode</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span>\n        <span class=\"token function\">updateMenuBar</span><span class=\"token punctuation\">(</span>todos<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">end</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">end</span>\n\nhs<span class=\"token punctuation\">.</span>hotkey<span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"cmd\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"alt\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ctrl\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"G\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">callGitLab</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">end</span><span class=\"token punctuation\">)</span>\n\nhs<span class=\"token punctuation\">.</span>timer<span class=\"token punctuation\">.</span><span class=\"token function\">doEvery</span><span class=\"token punctuation\">(</span>POLL_INTERVAL_MINUTES<span class=\"token operator\">*</span><span class=\"token number\">60</span><span class=\"token punctuation\">,</span> callGitLab<span class=\"token punctuation\">)</span>\n\n<span class=\"token function\">callGitLab</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>The code (IMO) is quite straightforward -</p>\n<ul>\n<li>We have a function <code class=\"language-text\">callGitLab</code>, that calls an API call to fetch the Todos and update the menubar when it is loaded.</li>\n<li>We set this function to refresh data every 15 minutes.</li>\n<li>We create a hotkey combination to manually refresh.</li>\n</ul>\n<p>I have been looking at Hammerspoon to build something for sometime now, and this does not even scratch the surface of whats possible.</p>\n<ul>\n<li>Credits to <a href=\"https://shantanugoel.com/\">Shantanu Goel</a> who built some cool things with Hammerspoon and his <a href=\"https://shantanugoel.com/2020/08/21/hammerspoon-multiscreen-window-layout-macos/\">latest post</a> gave me the idea (&#x26; motivation) to build this.</li>\n<li>Also, <a href=\"https://zzamboni.org/post/just-enough-lua-to-be-productive-in-hammerspoon-part-1/\">Just enough Lua to be productive in Hammerspoon</a> is a good series for someone who has no prior experience with Lua</li>\n</ul>","frontmatter":{"title":"Tracking GitLab Todos with Hammerspoon","date":"August 23, 2020","ogimage":null}}},"pageContext":{"slug":"/gitlab-todos-hammerspoon/","previous":{"fields":{"slug":"/solve-cross-origin-iframe-error/"},"frontmatter":{"title":"Solve the Cross-Origin Access error when working with iframes"}},"next":{"fields":{"slug":"/learning-rust/"},"frontmatter":{"title":"Learning Rust - The Interesting Parts"}}}},"staticQueryHashes":["426816048","983108779"]}