Created
October 12, 2023 23:58
-
-
Save Sija/0f0b7989355a9597bc0e5ebcd4bcde26 to your computer and use it in GitHub Desktop.
Poor man's @dependabot-style updater for ameba
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "colorize" | |
require "log" | |
require "yaml" | |
# --- | |
target_version = "~> 1.5.0" | |
root_dir = "~/Code" | |
paths = %w[ | |
any_hash.cr | |
backtracer | |
base62.cr | |
blurhash.cr | |
climate.cr | |
crystal-environment | |
debug.cr | |
git-rewrite-author | |
gphoto2.cr | |
gphoto2-web.cr | |
ipaddress.cr | |
jsonl.cr | |
ksuid.cr | |
money | |
raven.cr | |
retriable.cr | |
] | |
# --- | |
class Updater | |
GIT_COMMIT_MESSAGE = "Bump ameba version to %s" | |
GIT_BRANCH_NAME = "bump-ameba-version-to-%s" | |
getter path : Path | |
getter target_github_repo = "crystal-ameba/ameba" | |
getter target_version : String | |
getter? dry_run : Bool | |
def initialize(@path, @target_version, @dry_run = false) | |
@logger = Log.for(self.class) | |
end | |
def run : Nil | |
@logger.info { "Updating project: #{path.colorize.magenta}" } | |
shard_yml_path = path / "shard.yml" | |
unless File.exists?(shard_yml_path) | |
@logger.info { "Missing shard.yml, skipping" } | |
return | |
end | |
shard_yml = YAML.parse(File.read(shard_yml_path)) | |
version = shard_yml | |
.dig("development_dependencies", "ameba", "version") | |
.as_s | |
if version == @target_version | |
@logger.info { "Already up to date" } | |
return | |
end | |
@logger.info { "Found version: #{version.colorize.magenta}" } | |
git_branch_name = GIT_BRANCH_NAME % @target_version.gsub(/[^0-9.]+/, "") | |
git_commit_message = GIT_COMMIT_MESSAGE % @target_version | |
git_commit(path, git_branch_name, git_commit_message) do | |
update_shard_yml(shard_yml_path) | |
run_cmd "shards install" | |
end | |
@logger.info { "Version updated" } | |
rescue ex | |
@logger.error(exception: ex) { "Error while updating" } | |
end | |
private def run_cmd(cmd) | |
cmd.each_line do |line| | |
@logger.info { "Running command: #{line.colorize.magenta}" } | |
# XXX: Using `Process.run` might be better here | |
`#{line}` unless dry_run? | |
end | |
end | |
end | |
private def git_commit(path, branch_name, message, &) | |
Dir.cd(path) do | |
run_cmd <<-SH | |
git stash | |
git checkout -b #{branch_name} | |
SH | |
begin | |
yield | |
run_cmd <<-SH | |
git commit --all --message "#{message}" | |
git push --set-upstream origin #{branch_name} | |
gh pr create --assignee "@me" --title "#{message}" --body "" | |
SH | |
ensure | |
run_cmd <<-SH | |
git checkout - | |
git branch --delete #{branch_name} | |
git stash pop | |
SH | |
end | |
end | |
end | |
private def update_shard_yml(shard_yml_path) | |
updated_file = process shard_yml_path, | |
"development_dependencies", "ameba" | |
if dry_run? | |
@logger.info { "Updated shard.yml:\n\n#{updated_file.colorize.magenta}" } | |
else | |
@logger.debug { "Updated shard.yml:\n\n#{updated_file.colorize.magenta}" } | |
File.write(shard_yml_path, updated_file) | |
end | |
end | |
private def process(filepath, l1_key, l2_key) | |
l1_key = "#{l1_key}:" | |
l2_key = " #{l2_key}:" | |
l1 = false | |
l2 = false | |
lines = File.read(filepath).lines.map! do |line| | |
l1 = false if l1 && !line.starts_with? " " | |
if line == l1_key | |
l1 = true | |
next line | |
end | |
l2 = false if l2 && !line.starts_with? " " | |
if l1 && line == l2_key | |
l2 = true | |
next line | |
end | |
next line unless l2 | |
key, value = | |
line.split(':', 2).map!(&.strip) | |
sub = shard_yml_value(key) | |
next line unless sub | |
# XXX: bit nasty on the edges | |
line.sub("#{key}: #{value}", "#{key}: #{sub}") | |
end | |
lines.join('\n') + "\n" | |
end | |
private def shard_yml_value(key) | |
case key | |
when "git" then "https://github.com/#{@target_github_repo}.git" | |
when "github" then @target_github_repo | |
when "version" then @target_version | |
end | |
end | |
end | |
# --- | |
struct Formatter < Log::StaticFormatter | |
def run | |
@io << @entry.timestamp.to_rfc3339(fraction_digits: 6).colorize.dark_gray | |
string " " | |
@io << @entry.severity.label.rjust(6).colorize.green | |
string " " | |
if @entry.severity.error? | |
@io << @entry.message.colorize.red | |
else | |
@io << @entry.message | |
end | |
if ex = @entry.exception | |
@io << "\n\n" << ex.inspect_with_backtrace.colorize.red | |
end | |
end | |
end | |
Log.setup_from_env( | |
backend: Log::IOBackend.new(formatter: Formatter) | |
) | |
root_dir = Path[root_dir].expand(home: true) | |
paths.each do |path| | |
updater = Updater.new(root_dir / path, target_version, dry_run: true) | |
updater.run | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment