为了安全起见,Gemfile
中的内部Ruby gem应该始终在source
块中引用,因此它永远不会尝试从rubygems.org中获取它们。我想自动查找人们无法做到这一点的地方,所以我想解析Gemfile
,找到任何与我们的内部名称匹配的宝石,并检查rubygems.org不在他们可能的源列表中。
source 'https://rubygems.org'
gem 'rails'
gem 'my-private-gem1' # this should be in the source block below
source PRIVATE_GEM_REPO do
gem 'my-private-gem2'
end
我看到你可以解析Gemfile
Bundler::Definition.build('Gemfile', '', {})
但是在返回的数据结构中找不到显示每个gem可用/允许的源的任何内容
如果我包含Gemfile.lock
,我看到更多的源代码信息,但它似乎不正确,因为每个gem列出了我所有的源代码,不管它们是否在源代码块
Bundler::Definition.build('Gemfile', 'Gemfile.lock', {}).
locked_gems.
specs.
map {|g| [g.full_name, g.source.remotes.map(&:hostname).join(', ')]}
=> ["rails-6.0.3.4", "my.private.gemserver, rubygems.org"],
["my-private-gem1-1.0.0", "my.private.gemserver, rubygems.org"],
["my-private-gem2-1.0.0", "my.private.gemserver, rubygems.org"]]
关于如何解析Gemfile
以发现my-private-gem1
在源块之外的任何想法?
终于弄明白了,只是花了一些时间来研究Bundler的方法——以及一位同事的帮助。
Bundler::Definition.
build('Gemfile', '', nil).
dependencies.
map {|dep| [dep.name, dep.source&.remotes&.map(&:hostname)&.join(', ')]}
=>
[["rails", nil],
["my-private-gem1", nil],
["my-private-gem2", "my.private.gemserver"]]
现在我可以很容易地搜索得到的数据结构,找到任何没有锁定到我的私有gem服务器的私有gem。
引言
当我在写这个答案的时候,OP发现了一个特定于bundler的答案。然而,我在下面提供了一个更一般化的解决方案。此解决方案还提供了用户反馈,这可能使修复文件更容易。
通过列对齐查找候选宝石,使用白名单
如果你可以放心地假设你的Gemfile总是正确缩进的,那么KISS解决方案可能是简单地识别在组定义中没有缩进的gem。例如:
# example Gemfile to test against
GEMFILE = <<~'EOF'
source 'https://rubygems.org'
gem 'rails'
gem 'my-private-gem1' # this should be in the source block below
source PRIVATE_GEM_REPO do
gem 'my-private-gem2'
end
EOF
# gems that are acceptable in a non-group context
whitelist = Regexp.new %w[rails sass-rails webpacker].join(?|)
UngroupedGem = Struct.new :line_no, :line_txt, :gem_name
ungrouped_gems = []
GEMFILE.lines.each_with_index do |line_txt, line_no|
next if line_txt =~ whitelist or line_txt !~ /^s*gem/
gem_name = line_txt.match(/(?<=(['"]))(.*?)(?=1)/)[0]
ungrouped_gems.append(
UngroupedGem.new line_no.succ, line_txt, gem_name
).compact!
end
# tell the user what actions to take
if ungrouped_gems.any?
puts "Line No.tGem Name"
ungrouped_gems.each { printf "%dtt%sn", _1.line_no, _1.gem_name }
else
puts "No gems need to be moved."
end
在这个例子中,它将输出:
Line No. Gem Name 3 my-private-gem1 5 my-private-gem2
可以让你清楚地知道Gemfile中哪些行需要移动,以及涉及到哪些特定的gem。