This repository has been archived by the owner on Oct 17, 2021. It is now read-only.
generated from actions/container-action
-
Notifications
You must be signed in to change notification settings - Fork 6
/
entrypoint.rb
executable file
·172 lines (139 loc) · 5.64 KB
/
entrypoint.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env ruby
# frozen_string_literal: true
require "bundler"
Bundler.require
require "base64"
require "digest"
require "logger"
require "optparse"
require "tempfile"
logger = Logger.new($stdout)
logger.level = Logger::WARN
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: entrypoint.rb [options]"
opts.on("-r ", "--repository REPOSITORY", "The project repository") do |repository|
options[:repository] = repository
end
opts.on("-t", "--tap REPOSITORY", "The Homebrew tap repository") do |repository|
options[:tap] = repository
end
opts.on("-f", "--formula PATH", "The path to the formula in the tap repository") do |path|
options[:formula] = path
end
opts.on("-m", "--message MESSAGE", "The message of the commit updating the formula") do |message|
options[:message] = message.strip
end
opts.on_tail("-v", "--verbose", "Output more information") do
logger.level = Logger::DEBUG
end
opts.on_tail("-h", "--help", "Display this screen") do
puts opts
exit 0
end
end.parse!
begin
raise "GH_PERSONAL_ACCESS_TOKEN environment variable is not set" unless ENV["GH_PERSONAL_ACCESS_TOKEN"]
raise "missing argument: -r/--repository" unless options[:repository]
raise "missing argument: -t/--tap" unless options[:tap]
raise "missing argument: -f/--formula" unless options[:formula]
Octokit.middleware = Faraday::RackBuilder.new do |builder|
builder.use Faraday::Request::Retry, exceptions: [Octokit::ServerError]
builder.use Faraday::Response::RaiseError
builder.use Octokit::Middleware::FollowRedirects
builder.use Octokit::Response::FeedParser
builder.response :logger, logger, log_level: :debug do |logger|
logger.filter(/(Authorization\: )(.+)/, '\1[REDACTED]')
end
builder.adapter Faraday.default_adapter
end
client = Octokit::Client.new(access_token: ENV["GH_PERSONAL_ACCESS_TOKEN"])
repo = client.repo(options[:repository])
releases = repo.rels[:releases].get.data
raise "No releases found" unless (latest_release = releases.first)
tags = repo.rels[:tags].get.data
unless (tag = tags.find { |t| t.name == latest_release.tag_name })
raise "Tag #{latest_release.tag_name} not found"
end
PATTERN = /#{Regexp.quote(repo.name)}-#{Regexp.quote(latest_release.tag_name.delete_prefix("v"))}\.(?<platform>[^.]+)\.bottle\.((?<rebuild>[\d]+)\.)?tar\.gz/.freeze
assets = {}
rebuild = nil
latest_release.assets.each do |asset|
next unless (matches = asset.name.match(PATTERN))
next unless (platform = matches[:platform])
if rebuild && matches[:rebuild] && rebuild != matches[:rebuild]
logger.warn "Rebuild number for #{platform} (#{matches[:rebuild]}) doesn't match previously declared value (#{rebuild}), ignoring"
else
logger.info "Found rebuild number #{matches[:rebuild]} for #{platform}"
rebuild = rebuild || matches[:rebuild]
end
assets[platform] = Digest::SHA256.hexdigest(client.get(asset.browser_download_url))
end
blob = client.contents(options[:tap], path: options[:formula])
original_formula = Base64.decode64(blob.content)
buffer = Parser::Source::Buffer.new(original_formula, 1, source: original_formula)
builder = RuboCop::AST::Builder.new
ast = Parser::CurrentRuby.new(builder).parse(buffer)
rewriter = Parser::Source::TreeRewriter.new(buffer)
rewriter.transaction do
if (version = ast.descendants.find { |d| d.send_type? && d.method_name == :version })
rewriter.replace version.loc.expression, %Q(version "#{latest_release.tag_name}")
end
if (url = ast.descendants.find { |d| d.send_type? && d.method_name == :url })
rewriter.replace url.loc.expression,
%Q(url "#{repo.clone_url}", tag: "#{latest_release.tag_name}", revision: "#{tag.commit.sha}")
end
root_url = "https://github.com/#{repo.owner.login}/#{repo.name}/releases/download/#{latest_release.tag_name}"
bottles = assets.map do |platform, checksum|
%Q(sha256 cellar: :any, #{platform}: "#{checksum}")
end
bottle_expression = <<~RUBY
bottle do
root_url "#{root_url}"
#{" rebuild #{rebuild}" if rebuild}
#{bottles.join("\n ")}
end
RUBY
if (bottle = ast.descendants.find { |d| d.block_type? && d.send_node&.method_name == :bottle })
if assets.empty?
rewriter.replace bottle.loc.expression, ""
else
rewriter.replace bottle.loc.expression, bottle_expression
end
elsif assets.any?
for node_name in %i[license url] do
(insert_after = ast.descendants.find { |d| d.send_type? && d.method_name == node_name })
rewriter.insert_after insert_after.loc.expression, "\n\n#{bottle_expression}"
break
end
end
end
updated_formula = rewriter.process
begin
tempfile = Tempfile.new("#{repo.name}.rb")
File.write tempfile, updated_formula
rubocop_config = "/Homebrew/Library/.rubocop.yml"
raise "Can't find rubocop config: #{rubocop_config}" unless File.exist?(rubocop_config)
logger.debug `rubocop -c #{rubocop_config} -x #{tempfile.path}`
updated_formula = File.read(tempfile)
ensure
tempfile.close
tempfile.unlink
end
logger.info updated_formula
if original_formula == updated_formula
logger.warn "Formula is up-to-date"
exit 0
else
commit_message = options[:message].empty? ? "Update #{repo.name} to #{latest_release.tag_name}" : options[:message]
logger.info commit_message
client.update_contents(options[:tap],
options[:formula],
commit_message,
blob.sha,
updated_formula)
end
rescue => e
logger.fatal(e)
exit 1
end