通过 Rakefile 运行 SSH 命令

TL;DR:CocoaDocs 的命令以前通过登录执行,现在通过 rake 命令执行。

CocoaDocs 运行着大量的 CocoaPods 基础设施。它是一匹任劳任怨的马,让我们能够提供呈现的 README/CHANGELOG问题状态更新

我一直在手动 ssh 登录服务器以执行命令,已经几年了,这有点像一项繁重的家务活。不过,随着时间的推移,我习惯了。随着越来越多的人开始帮助维护 CocoaDocs,很明显,它需要从晦涩难懂的知识转变为易于发现的命令。

展示代码:c7be695...a00338d

我最初探索了使用 Mina 的想法,让我们像对待 heroku 一样对待 CocoaDocs。我花了几个小时来设置它,但从未设法获得一个 可用的原型。最终,我开始寻找替代方案。

我找到了 net-ssh,它很好地提醒了 ruby 社区有多么古老,因为文档来自 2004 年。我使用它通过极少的代码连接到服务器

require 'net/ssh'

Net::SSH.start('api.cocoadocs.org', 'cocoadocs', :password => "hahayeahright") do |ssh|
  output = ssh.exec!("hostname")
  puts output
end

这足以开始。不过,一旦我开始,就遇到了一个问题。每个命令都是无状态执行的。从原理上讲,这意味着你的会话不会停留在同一个文件夹中,而且你不会拥有正常的 shell 设置。我开始尝试做 shell 会做的一切,比如 source ~/.zshrc 等。不切实际。

在放弃 exec 函数后,我在 duckduckgo 上搜索替代方案,并在文档中找到了 关于 shell 的一章。但是,文档已过时,而且代码不存在。幸运的是,它刚刚被分离到一个新的 gem 中:net-ssh-shell。这意味着我们可以执行

require 'net/ssh'
require 'net/ssh/shell'

Net::SSH.start('api.cocoadocs.org', 'cocoadocs', :password => "hahayeahright") do |ssh|
  ssh.shell do |sh|
    sh.execute 'hostname'
  end
end

它按预期执行命令,就好像你已经登录了一样。完美。有了它,我做了一些小的重构,将所有内容转换为一个函数,该函数将一些命令作为数组。

 def run_ssh_commands commands
   puts "Connecting to api.cocoadocs.org:"
   Net::SSH.start('api.cocoadocs.org', 'cocoadocs') do |ssh|
     ssh.shell do |sh|
       sh.execute 'cd cocoadocs.org'
       commands.each do |command|
         puts command.yellow
         sh.execute command
       end
       sh.execute 'exit'
     end
   end
  end

我在提交的命令的末尾添加了一个 exit 命令来关闭会话,就是这样。现在,维护人员可以在计算机上轻松运行命令,而无需领域知识。他们只需要知道 bundle exec rake -T 会提供有用的任务。鉴于我们在所有项目中都使用 Rakefile,因此这种知识是隐含的。哇!

所以,下次你听到有人抱怨你已经习惯的家务时,请注意并尝试通过自动化解决问题。