用Ruby、Keyboard Maestro和1Password CLI实现GitHub API调用的自动化

246 阅读5分钟

Mac上的Ruby的 "终极 "版本的好处之一是可以进入GitHub的私有仓库。作为一个开发者--尤其是一个喜欢自动化的开发者--我很想尝试完全自动化地邀请新的Ultimate客户进入该仓库。

要做到这一点,需要实现一个自定义的结账,捕捉客户的GitHub用户名,这样我就可以把它传递给Paddle结账流程。不幸的是,Paddle不支持在其结账中添加自定义字段。

从那里,我只需要在我现有的接收Paddle webhook的小型Rails应用中添加几行代码。我目前正在使用它来自动添加/更新我ConvertKit账户中的客户,这样我就可以根据他们购买的产品轻松地对他们进行细分,计算他们的终身价值,自动填充他们的升级优惠券的字段,以及其他有用的东西。

从Paddle有效载荷中提取GitHub用户名后,我将使用octokitgem将客户作为只读合作者添加到 repo中。就像这样:

client = Octokit::Client.new(access_token: github_token)
client.add_collaborator(repo, username, permission: 'pull')

鉴于我每周只收到几份Ultimate订单,我想我应该练习一下打火石的艺术,暂时手动邀请每个用户。然而,这并不意味着我每次都要以缓慢的方式进行。

当一个客户给我发电子邮件要求访问时,我所要做的只是从他们发给我的电子邮件中复制他们的用户名,然后我按下⌃-⌥-⌘-A ,就完成了! 这种自动化使用键盘大师、GitHub API和1Password CLI

下面是键盘大师的宏的样子:

虽然你可以直接在键盘大师中运行脚本,但我选择从iTerm的项目文件夹中运行脚本,因为那里已经安装了octokit gem。下面是add_collab.rb 文件的样子。

require 'octokit'

def repo
  "rubyonmac/rom-ultimate"
end

def github_token
  `op item get "add_collab GH token" --fields label=notesPlain`
end

def client
  @client ||= Octokit::Client.new(access_token: github_token)
end

customer_github_username = ARGV[0]

puts "adding collaborator #{customer_github_username}"
response = client.add_collaborator(repo, customer_github_username, permission: 'pull')
puts "response: #{response}"

而这里是Gemfile:

source "https://rubygems.org"
ruby File.read(".ruby-version").strip
gem "octokit"

如果你读过我以前的自动化指南,你会记得它带有许多方便的标记,这些标记是数据的占位符,否则就需要复杂的代码来获取。在这种情况下,我使用%SystemClipboard% 令牌来传递用户名(我从客户的电子邮件中复制的),作为Ruby脚本的一个参数。当你向Ruby脚本传递一个参数时,你可以通过ARGV[0]

出于安全考虑,我需要向Octokit gem提供一个与我的账户相关的有效的GitHub令牌,以便能够进行这个特定的GitHub API调用。我创建这个令牌的方法是添加一个新的个人访问令牌,并给它适当的作用域:admin:orgrepo 。我还设置它在30天后失效。

因为我在家里使用两台Mac,所以我把所有的项目都放在GitHub上,这样我可以很容易地在两台电脑上获得最新的代码。即使在我的私人仓库里,我也会把包含秘密的文件(如GitHub令牌)gitignore,以增加安全性,也是出于习惯。

在过去,这需要将秘密文件(如.envrc 如果使用direnv)从一台电脑复制到另一台电脑,然后在每次更新时在两台电脑上更新。它还需要记住在外部驱动器上备份gitignored文件,如果我有一天更换了我的Mac。

但现在我发现了1Password CLI,我可以摆脱.envrc ,我不需要担心来回复制文件或备份任何东西。我可以从我的1Password账户中获取令牌,这在两台计算机上都是自动可用的。我的电脑上不再有任何秘密以纯文本形式存储(除了1Password),而且如果我想的话,我可以安全地将这个 repo 公开。

因此,代替通常的ENV['GITHUB_TOKEN'] ,我可以用这个命令获取令牌:

`op item get "add_collab GH token" --fields label=notesPlain`

在Ruby中,你可以通过在命令周围加上反斜线来运行shell命令。你可能也熟悉system命令,但它并不返回命令的输出。如果命令成功,它返回true (退出状态为0)。因为我想得到命令的实际输出,所以我需要反记号。

正如你可能从op 命令中猜到的那样,令牌被存储在1Password中名为 "add_collab GH token "的安全笔记中。我通过阅读item get的文档弄清了完整的命令,然后一开始只运行这个命令:

op item get "add_collab GH token"

它的返回结果是这样的:

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

这就是我如何知道我需要的labelnotesPlain 。 这里又是完整的命令:

op item get "add_collab GH token" --fields label=notesPlain

为了让这个命令更稳健,我会在命令的末尾加上2>&1 ,将stderr 重定向到stdout ,然后将结果存储在一个变量中,只在没有错误的情况下调用GitHub API。就像这样:

def github_token
  token = `op item get "add_collab GH token" --fields label=notesPlain 2>&1`
  if token.include?("ERROR")
    puts "Failed to fetch token from 1Password: #{token}"
    nil
  else
    token
  end
end

def client
  @client ||= Octokit::Client.new(access_token: github_token)
end

if github_token
  puts "adding collaborator #{ARGV[0]}"
  response = client.add_collaborator(repo, ARGV[0], permission: 'pull')
  puts "response: #{response}"
end

就这样,你就有了。多亏了 Keyboard Maestro、1Password CLI、Octokit gem 和几行 Ruby,与通过 GitHub 网站手动操作相比,我为每个客户节省了大约 30 秒。到目前为止,有49个终极版客户(我在2022年7月底刚刚推出了终极版),到目前为止,大约节省了25分钟的时间