<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moncef Belyamani</title>
    <description>The latest articles on DEV Community by Moncef Belyamani (@monfresh).</description>
    <link>https://dev.to/monfresh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F920050%2Fa3bac32e-cf51-42d7-905c-5f47c0f3e6a3.jpeg</url>
      <title>DEV Community: Moncef Belyamani</title>
      <link>https://dev.to/monfresh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/monfresh"/>
    <language>en</language>
    <item>
      <title>How to Install Ruby 2.6.x on macOS 13 (Ventura) and Monterey</title>
      <dc:creator>Moncef Belyamani</dc:creator>
      <pubDate>Tue, 21 Feb 2023 19:06:37 +0000</pubDate>
      <link>https://dev.to/monfresh/how-to-install-ruby-26x-on-macos-13-ventura-and-monterey-12c2</link>
      <guid>https://dev.to/monfresh/how-to-install-ruby-26x-on-macos-13-ventura-and-monterey-12c2</guid>
      <description>&lt;p&gt;"How can I install Ruby 2.6.x on a Mac M1/M2?" I get asked this question a lot, and I see it often in the various online Ruby hangouts. People try all kinds of things but no one seems to be able to succeed. Some people say to use Rosetta, and others say forget about 2.6 and update your project to 2.7.&lt;/p&gt;

&lt;p&gt;The truth is that it is possible to install Ruby 2.6 on an Apple Silicon Mac, and in this article I'll show you 3 different ways to do that. You can skip directly to each solution with the links below, but I highly recommend reading the whole article to better understand how Ruby installation works on a Mac, and why most solutions people try don't work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Ruby 2.6.10 with Ruby on Mac Ultimate&lt;/li&gt;
&lt;li&gt;Install Ruby 2.6.10 with Homebrew&lt;/li&gt;
&lt;li&gt;Downgrade to version 13.4 of the command line tools (does not work with Ventura)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do your solutions only work with 2.6.10? I need an older version!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is another common source of confusion because people don't understand how Ruby versioning works. They get stuck because they think they &lt;strong&gt;have&lt;/strong&gt; to use the version of Ruby that's specified in the project's &lt;code&gt;.ruby-version&lt;/code&gt; and/or &lt;code&gt;Gemfile&lt;/code&gt;. Instead, it's recommended to update the project to at least the latest patch version (the third digit). &lt;/p&gt;

&lt;p&gt;For example, if your project is currently using Ruby 2.6.6, or any version of 2.6 lower than 2.6.10, the first thing I recommend you do is update it to 2.6.10. And then the next thing you want to prioritize is updating it to 2.7.7 because Ruby 2.6 reached end of life in March 2022, which means it has known bugs and security issues that will never be fixed. Note that you can also go straight from 2.6.x to 2.7.7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is super important to understand, so please read my guide that explains &lt;a href="https://www.rubyonmac.dev/how-to-upgrade-the-ruby-version-in-your-project" rel="noopener noreferrer"&gt;how and why to upgrade the Ruby version in your project&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Ruby installation works on a Mac
&lt;/h2&gt;

&lt;p&gt;Some people will tell you that Ruby 2.6 is not compatible with Apple Silicon Macs. Yet, Ventura comes preinstalled with Ruby 2.6.10 on all Macs. That proves that it is possible to install it on Ventura on both Intel and Apple Silicon Macs.&lt;/p&gt;

&lt;p&gt;However, this version of Ruby preinstalled by Apple is not meant to be used for development. Read my article that goes over &lt;a href="https://www.moncefbelyamani.com/why-you-shouldn-t-use-the-system-ruby-to-install-gems-on-a-mac/" rel="noopener noreferrer"&gt;5 reasons why you shouldn't use the system Ruby on macOS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead, you'll want to use a special tool that can install a separate version of Ruby that doesn't interfere with the one that Apple installed. These tools, known as version managers, can install multiple versions of Ruby at the same time, and let you easily switch between them. The most popular ones are asdf, chruby/ruby-install, frum, rbenv/ruby-build, and rvm.&lt;/p&gt;

&lt;p&gt;The problem is that these version managers (when used out of the box with their default settings) fail to install Ruby 2.6.x on any Mac running on macOS Ventura (13.x), and in some cases on the latest version of Monterey (12.6.x) that has version 14 or higher of Apple's command line tools (CLT).&lt;/p&gt;

&lt;p&gt;Assuming you have Homebrew installed, you can check which version of the CLT you have by running &lt;code&gt;brew config&lt;/code&gt;, and then look towards the bottom for the lines that start with &lt;code&gt;CLT:&lt;/code&gt; and/or &lt;code&gt;Xcode:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The reason why some version managers can't install certain versions of Ruby is because they all compile Ruby from scratch, and whether or not the installation succeeds depends on five main factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CLT version&lt;/li&gt;
&lt;li&gt;The macOS version&lt;/li&gt;
&lt;li&gt;The Mac chip (Intel or Apple Silicon)&lt;/li&gt;
&lt;li&gt;How the version manager configured Ruby&lt;/li&gt;
&lt;li&gt;Whether or not you have prerequisite tools installed (many version managers don't install them for you)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each version manager configures Ruby differently, which is why you might be able to install a particular version with &lt;code&gt;ruby-install&lt;/code&gt; for example, but not with &lt;code&gt;asdf&lt;/code&gt; or &lt;code&gt;rbenv&lt;/code&gt;. Note that these version managers allow you to override some or all Ruby configuration settings, but the vast majority of people use the default settings. This makes sense because modifying anything would require deep knowledge of how Ruby configuration and compilation works.&lt;/p&gt;

&lt;p&gt;In addition, the way Ruby needs to be configured depends on the Ruby version. However, most version managers use the same settings for all versions. One exception is &lt;code&gt;ruby-build&lt;/code&gt; (the tool that both &lt;code&gt;rbenv&lt;/code&gt; and &lt;code&gt;asdf&lt;/code&gt; use to install Ruby) which uses an appropriate version of OpenSSL depending on the Ruby version. That's not enough in some cases, though, and the fact that &lt;code&gt;ruby-build&lt;/code&gt; compiles its own version of OpenSSL has some downsides.&lt;/p&gt;

&lt;p&gt;That's why I built &lt;a href="https://www.rubyonmac.dev" rel="noopener noreferrer"&gt;Ruby on Mac&lt;/a&gt;. It's the result of eleven years of helping thousands of people set up a reliable Ruby dev environment on their Mac. I also continuously spend hundreds of hours researching and testing various Ruby versions on 4 different Macs using all kinds of scenarios. Ruby on Mac guarantees a successful installation of any supported Ruby version on macOS 13 (Ventura), 12 (Monterey), and 11 (Big Sur). For now, that includes 2.6.10 and above with Ultimate, and 2.7.x and above with Prime. I'm working on adding support for super old Ruby versions like 2.3.x, but I need to do more testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about Rosetta?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some people will tell you they found a solution using Rosetta, but that means one of these two results: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They end up doing all of their dev work with Rosetta, which is a shame not to take full advantage of the Apple Silicon chip.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They try to set up two dev environments — one with Rosetta, and one in native mode — and they inevitably run into all kinds of issues. Then they waste time either trying to fix them or removing everything and starting over from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news is that if you've been using Rosetta to work on a Ruby 2.6.x project, you can use Ruby on Mac's "reset" mode, which will safely back up, then clean up your dev setup in 1 minute, and then you can run it in "normal" mode to reinstall everything from scratch in native mode.&lt;/p&gt;

&lt;p&gt;Now that you have a basic understanding of what can cause Ruby installation to fail, let's go over three solutions for installing Ruby 2.6.10 on your Mac, from easiest to most time-consuming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Ruby 2.6.10 with &lt;a href="https://www.rubyonmac.dev/pricing/" rel="noopener noreferrer"&gt;Ruby on Mac Ultimate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install Ruby 2.6.10 with Homebrew&lt;/li&gt;
&lt;li&gt;Downgrade to version 13.4 of the command line tools (doesn't work on Ventura)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install Ruby 2.6.10 with Ruby on Mac Ultimate
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://www.rubyonmac.dev/pricing/" rel="noopener noreferrer"&gt;Ruby on Mac Ultimate&lt;/a&gt;, installing Ruby 2.6.10 on Ventura or Monterey is as easy as running this command (after installing Ruby on Mac):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rom install ruby 2.6.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't have to do anything else to configure it, and you don't have to mess with your &lt;code&gt;PATH&lt;/code&gt; or shell file to be able to switch to other Ruby versions.&lt;/p&gt;

&lt;p&gt;To start using 2.6.10, you'll quit and restart your terminal, then run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chruby 2.6.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Ruby 2.6.10 with Homebrew
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; if you haven't already&lt;/li&gt;
&lt;li&gt;Install Ruby 2.6.10: &lt;code&gt;brew install ruby@2.6&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow the instructions for setting your &lt;code&gt;PATH&lt;/code&gt;. For example, Homebrew will say something like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;By default, binaries installed by gem will be placed into:
  /opt/homebrew/lib/ruby/gems/2.6.0/bin

You may want to add this to your PATH.

If you need to have ruby first in your PATH, run:
  echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' &amp;gt;&amp;gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason Homebrew is able to install 2.6.10 is because this is a pre-built version of Ruby that was compiled with version 13.3 of the command line tools. However, note that it's not officially supported.&lt;/p&gt;

&lt;p&gt;Unless you know what you're doing, in order to use the Homebrew Ruby, you'll need to disable any other version manager you might have used before (such as asdf, chruby, frum, rbenv, or rvm). And you'll only be able to use 2.6.10 with this setup. You won't be able to switch to other versions that you might have installed with another version manager, unless you make changes to your shell file to disable the Homebrew Ruby and turn your version manager setup back on. You'll have to keep doing this each time you want to switch between 2.6.10 and other versions.&lt;/p&gt;

&lt;p&gt;This is meant as a temporary solution so that you can run your project with 2.6.10 and then update it to 2.7.7, and then 3.1.3, and so on. Also, note that either way, you'll need to update your project to at least 2.6.10. There's absolutely no reason to use any other version of Ruby 2.6.x. For security reasons, it's recommended to make sure your apps are running the latest version in a series. For 2.6, it's 2.6.10, for 2.7, it's 2.7.7, then 3.0.5, 3.1.3, and 3.2.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downgrade to version 13.4 of the command line tools
&lt;/h2&gt;

&lt;p&gt;This is not possible on macOS Ventura (13.x), so don't waste your time trying. It will probably take you less time to update your project to 2.7.7 than it would to downgrade from Ventura to Monterey. &lt;/p&gt;

&lt;p&gt;If you're on macOS Monterey, follow the steps below to download and install version 13.4 of the command line tools. Note that this is not guaranteed to work, depending on which version of Monterey you're running. I had success with macOS 12.1, but some issues with 12.6.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note that it should never be necessary to download the huge 7GB Xcode app unless you're building macOS and iOS apps. In other words, if you're never going to use the Xcode app itself, all you need are the standalone Command Line Tools.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/download/all/?q=xcode" rel="noopener noreferrer"&gt;Download "Command Line Tools for Xcode 13.4"&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install them, but keep the DMG when it asks you if you want to Trash it, just in case you need to install them again.&lt;/li&gt;
&lt;li&gt;Check that Homebrew is using the correct CLT with &lt;code&gt;brew config&lt;/code&gt;. You should see &lt;code&gt;CLT: 13.4.0.0.1.1651278267&lt;/code&gt;. If not, try reinstalling them.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;brew doctor&lt;/code&gt; to make sure everything is fine. If not, follow Homebrew's instructions for fixing issues.&lt;/li&gt;
&lt;li&gt;Reinstall all Ruby-related tools with Homebrew:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew reinstall automake bison gdbm libffi libyaml openssl@1.1 openssl@3 readline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install Ruby 2.6.10 with your favorite Ruby version manager. If you haven't yet installed a version manager, you can either &lt;a href="https://www.rubyonmac.dev/pricing/" rel="noopener noreferrer"&gt;buy Ruby on Mac&lt;/a&gt;, which will set everything up for you in 15 minutes, or spend an hour following my &lt;a href="https://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac/" rel="noopener noreferrer"&gt;step-by-step guide for installing Ruby on a Mac&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>cybersecurity</category>
      <category>security</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Automate GitHub API Calls With Ruby, Keyboard Maestro, and 1Password CLI</title>
      <dc:creator>Moncef Belyamani</dc:creator>
      <pubDate>Wed, 07 Sep 2022 15:38:59 +0000</pubDate>
      <link>https://dev.to/monfresh/automate-github-api-calls-with-ruby-keyboard-maestro-and-1password-cli-2ge5</link>
      <guid>https://dev.to/monfresh/automate-github-api-calls-with-ruby-keyboard-maestro-and-1password-cli-2ge5</guid>
      <description>&lt;p&gt;One of the perks of the "Ultimate" version of &lt;a href="https://www.rubyonmac.dev/#ultimate" rel="noopener noreferrer"&gt;Ruby on Mac&lt;/a&gt; is access to the private GitHub repo. As a developer — especially one who loves automation — it was tempting to try to completely automate inviting new Ultimate customers to the repo.&lt;/p&gt;

&lt;p&gt;To do that would require implementing a custom checkout that captures the customer's GitHub username, so I can then pass it on to the &lt;a href="https://paddle.com" rel="noopener noreferrer"&gt;Paddle&lt;/a&gt; checkout flow. Paddle unfortunately doesn't support adding custom fields to their checkout.&lt;/p&gt;

&lt;p&gt;From there, I would only need to add a few lines of code to my existing small Rails app that receives the Paddle webhook. I'm currently using it to automatically add/update customers in my &lt;a href="https://convertkit.com" rel="noopener noreferrer"&gt;ConvertKit&lt;/a&gt; account, so I can easily segment them based on which product they bought, calculate their lifetime value, auto-populate a field with their upgrade coupon, and other useful things.&lt;/p&gt;

&lt;p&gt;After extracting the GitHub username from the Paddle payload, I would use the &lt;a href="https://github.com/octokit/octokit.rb" rel="noopener noreferrer"&gt;octokit&lt;/a&gt; gem to add the customer as a read-only collaborator to the repo. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Octokit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;access_token: &lt;/span&gt;&lt;span class="n"&gt;github_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_collaborator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;permission: &lt;/span&gt;&lt;span class="s1"&gt;'pull'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that I'm only getting a few orders of Ultimate per week, I thought I would practice &lt;a href="https://stackingthebricks.com/the-fine-art-of-flintstoning/" rel="noopener noreferrer"&gt;the fine art of flintstoning&lt;/a&gt; and invite each user manually for now. However, that doesn't mean I have to do it the slow way each time. &lt;/p&gt;

&lt;p&gt;When a customer emails me to request access, all I have to do is copy their username from the email they sent me, then I press &lt;code&gt;⌃-⌥-⌘-A&lt;/code&gt;, and it's done! &lt;br&gt;
This automation uses &lt;a href="https://www.keyboardmaestro.com/main/" rel="noopener noreferrer"&gt;Keyboard Maestro&lt;/a&gt;, the GitHub API, and &lt;a href="https://developer.1password.com/docs/cli/" rel="noopener noreferrer"&gt;1Password CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what the Keyboard Maestro macro looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.moncefbelyamani.com/images/km_macro_add_github_collaborator.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.moncefbelyamani.com%2Fimages%2Fkm_macro_add_github_collaborator-compressed.jpg" alt="Keyboard Maestro Macro to add a collaborator to a private GitHub repo" width="750" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While you can run scripts directly in Keyboard Maestro, I chose to run the script from the project folder in iTerm because the octokit gem is already installed there. Here's what the &lt;code&gt;add_collab.rb&lt;/code&gt; file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'octokit'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;repo&lt;/span&gt;
  &lt;span class="s2"&gt;"rubyonmac/rom-ultimate"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;github_token&lt;/span&gt;
  &lt;span class="sb"&gt;`op item get "add_collab GH token" --fields label=notesPlain`&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;
  &lt;span class="vi"&gt;@client&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Octokit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;access_token: &lt;/span&gt;&lt;span class="n"&gt;github_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;customer_github_username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"adding collaborator &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;customer_github_username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_collaborator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_github_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;permission: &lt;/span&gt;&lt;span class="s1"&gt;'pull'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"response: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the &lt;code&gt;Gemfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"https://rubygems.org"&lt;/span&gt;
&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".ruby-version"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"octokit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've read my previous &lt;a href="https://www.moncefbelyamani.com/tags/keyboard-maestro" rel="noopener noreferrer"&gt;automation guides featuring Keyboard Maestro&lt;/a&gt;, you'll recall that it comes with many handy &lt;a href="https://wiki.keyboardmaestro.com/Tokens" rel="noopener noreferrer"&gt;tokens&lt;/a&gt; that are placeholders for data that would otherwise require complicated code to fetch. In this case, I'm using the &lt;code&gt;%SystemClipboard%&lt;/code&gt; token to pass in the username (that I copied from the customer's email) as an argument to the Ruby script. When you pass an argument to a Ruby script, you can access it via &lt;code&gt;ARGV[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For security reasons, I need to provide the Octokit gem with a valid GitHub token associated with my account to be able to make this particular GitHub API call. The way I created this token was by adding a new &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token" rel="noopener noreferrer"&gt;Personal Access Token&lt;/a&gt; to my GitHub account, and giving it the appropriate scopes: &lt;code&gt;admin:org&lt;/code&gt; and &lt;code&gt;repo&lt;/code&gt;. I also set it to expire after 30 days.&lt;/p&gt;

&lt;p&gt;Because I use two Macs at home, I keep all my projects on GitHub so I can easily have the latest code on both computers. However, I gitignore files that contain secrets (like GitHub tokens), even on my private repos. I do this for added security, and also out of habit.&lt;/p&gt;

&lt;p&gt;In the past, this would require copying the secret file (such as &lt;code&gt;.envrc&lt;/code&gt; if using &lt;a href="https://direnv.net" rel="noopener noreferrer"&gt;direnv&lt;/a&gt;) from one computer to the other, and then updating it on both computers each time I renew it. It also requires remembering to back up the gitignored file on an external drive if I ever replace my Macs.&lt;/p&gt;

&lt;p&gt;But now that I discovered the 1Password CLI, I can get rid of &lt;code&gt;.envrc&lt;/code&gt;, and I don't need to worry about copying files back and forth or backing anything up. I can fetch the token from my 1Password account, which is automatically available on both computers. &lt;/p&gt;

&lt;p&gt;What I like most about this approach is that &lt;strong&gt;I no longer need to have any secrets stored in plain text on my computer (except in 1Password)!&lt;/strong&gt; I can also safely make this repo public if I wanted to.&lt;/p&gt;

&lt;p&gt;So, instead of the usual &lt;code&gt;ENV['GITHUB_TOKEN']&lt;/code&gt;, I can fetch the token with the 1Password CLI &lt;code&gt;op&lt;/code&gt; tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;github_token&lt;/span&gt;
  &lt;span class="sb"&gt;`op item get "add_collab GH token" --fields label=notesPlain`&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Ruby, you can run shell commands by surrounding them with backticks. You might also be familiar with the &lt;a href="https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-system" rel="noopener noreferrer"&gt;system&lt;/a&gt; command, but it doesn't return the output of the command. It returns &lt;code&gt;true&lt;/code&gt; if the command succeeds (with a zero exit status). Since I want the actual output of the command, I need the backticks.&lt;/p&gt;

&lt;p&gt;As you might guess from the &lt;code&gt;op&lt;/code&gt; command, the token is stored in a Secure Note in 1Password called "add_collab GH token". I figured out the full command by reading the documentation for &lt;a href="https://developer.1password.com/docs/cli/reference/management-commands/item#item-get" rel="noopener noreferrer"&gt;item get&lt;/a&gt;, and then running just this command at first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;op item get &lt;span class="s2"&gt;"add_collab GH token"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returned something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ID:          some_unique_id
Title:       add_collab GH token
Vault:       Personal
Created:     4 days ago
Updated:     4 days ago by Moncef Belyamani
Favorite:    false
Version:     1
Category:    SECURE_NOTE
Fields:
  notesPlain:    my_github_token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's how I knew that the &lt;code&gt;label&lt;/code&gt; I needed was &lt;code&gt;notesPlain&lt;/code&gt;. Here's the full command again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;op item get &lt;span class="s2"&gt;"add_collab GH token"&lt;/span&gt; &lt;span class="nt"&gt;--fields&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;notesPlain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this more robust, I could redirect &lt;code&gt;stderr&lt;/code&gt; to &lt;code&gt;stdout&lt;/code&gt; by adding &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; to the end of the command, then store the result in a variable, and only call the GitHub API if there's no error. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;github_token&lt;/span&gt;
  &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`op item get "add_collab GH token" --fields label=notesPlain 2&amp;gt;&amp;amp;1`&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ERROR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Failed to fetch token from 1Password: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;
  &lt;span class="vi"&gt;@client&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Octokit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;access_token: &lt;/span&gt;&lt;span class="n"&gt;github_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;github_token&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"adding collaborator &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;customer_github_username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_collaborator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_github_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;permission: &lt;/span&gt;&lt;span class="s1"&gt;'pull'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"response: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason for redirecting &lt;code&gt;stderr&lt;/code&gt; to the output is to be able to read and store the error message. Without the redirection, if there's an error, &lt;code&gt;token&lt;/code&gt; will just be an empty string.&lt;/p&gt;

&lt;p&gt;Alternatively, I could still use &lt;code&gt;direnv&lt;/code&gt; by calling the &lt;code&gt;op&lt;/code&gt; command in &lt;code&gt;.envrc&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;op item get &lt;span class="s2"&gt;"add_collab GH token"&lt;/span&gt; &lt;span class="nt"&gt;--fields&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;notesPlain&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since there's no secrets in it anymore, I would be able to commit &lt;code&gt;.envrc&lt;/code&gt; to the repo. And if there's an error fetching the token, I would see it after running &lt;code&gt;direnv allow&lt;/code&gt;. This approach would be handy for projects that depend on secrets being stored in env vars, like the &lt;code&gt;RAILS_MASTER_KEY&lt;/code&gt; in Rails apps. &lt;/p&gt;

&lt;p&gt;To save even more time, I could automate the process of verifying that the person who is requesting access did indeed buy &lt;a href="https://www.rubyonmac.dev/#ultimate" rel="noopener noreferrer"&gt;Ruby on Mac&lt;/a&gt; Ultimate. Again, Keyboard Maestro makes this easy with the &lt;code&gt;%MailSender%&lt;/code&gt; token. &lt;/p&gt;

&lt;p&gt;I would then pass this email address as a second argument to my Ruby script, and then use the ConvertKit API via the &lt;a href="https://github.com/hookengine/convertkit-ruby" rel="noopener noreferrer"&gt;convertkit-ruby&lt;/a&gt; gem to see if there's an existing entry for that email address, and that the custom field that indicates they purchased Ultimate is filled in.&lt;/p&gt;

&lt;p&gt;There you have it. Thanks to Keyboard Maestro, 1Password CLI, the Octokit gem, and a few lines of Ruby, I save about 30 seconds per customer compared to doing everything manually via the GitHub site. With 52 Ultimate customers so far (I just launched the Ultimate version in late July 2022), that's almost 30 minutes saved so far!&lt;/p&gt;

&lt;p&gt;If you enjoyed this post and want more free automation ideas and tutorials, &lt;a href="https://www.moncefbelyamani.com/newsletter" rel="noopener noreferrer"&gt;sign up for my weekly newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>productivity</category>
      <category>github</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
