Skip to content

Instantly share code, notes, and snippets.

@luizkowalski
Last active August 30, 2024 18:46
Show Gist options
  • Select an option

  • Save luizkowalski/6e7eb3b318dacc01c80754d2599f47ee to your computer and use it in GitHub Desktop.

Select an option

Save luizkowalski/6e7eb3b318dacc01c80754d2599f47ee to your computer and use it in GitHub Desktop.

Revisions

  1. luizkowalski revised this gist Aug 30, 2024. 1 changed file with 17 additions and 3 deletions.
    20 changes: 17 additions & 3 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@
    CONFIG = YAML.load_file("config/deploy.yml")
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30
    UNSUPPORTED = ["gcr.io", "ghcr.io"].freeze
    UNSUPPORTED = ["ghcr.io"].freeze

    # These suffixes are just different versions of the same image.
    # When it comes to versioning, we only care about the version number.
    @@ -38,20 +38,32 @@ def scrape_tags(repository, service)
    end
    end

    def scrape_google_registry(repository)
    response = Net::HTTP.get_response(URI("https://gcr.io/v2/#{repository}/tags/list"))

    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)

    data["tags"]
    else
    puts "💣 Error: #{response.code}\n\n"
    end
    end

    ACCESSORIES.each_value do |config| # rubocop:disable Metrics/BlockLength
    image, current_tag = config["image"].split(":")

    next puts "⏭️ Skipping #{image}, no tag specified\n\n" if current_tag.nil?

    unsupported_message = <<~MESSAGE
    😓 Skipping #{image}, not supported...yet
    You might want to manually check for updates at https://#{image}
    You might want to manually check for updates at 🛜 https://#{image}
    MESSAGE

    next puts unsupported_message if image.start_with?(*UNSUPPORTED)

    repository = image.sub(%r{lscr.io/|quay.io/}, "").then do |repo|
    repository = image.sub(%r{lscr.io/|quay.io/|gcr.io/}, "").then do |repo|
    repo.include?("/") ? repo.split("/") : ["library", repo]
    end.join("/")

    @@ -60,6 +72,8 @@ def scrape_tags(repository, service)
    tags = case image
    when /quay.io/
    scrape_tags(repository, "quay")
    when /gcr.io/
    scrape_google_registry(repository)
    else
    scrape_tags(repository, "dockerhub")
    end
  2. luizkowalski revised this gist Aug 30, 2024. 1 changed file with 49 additions and 24 deletions.
    73 changes: 49 additions & 24 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    #!/usr/bin/env ruby
    # frozen_string_literal: true

    # lives in .kamal/update
    # Lives in .kamal/update

    require "json"
    require "net/http"
    @@ -11,44 +11,69 @@
    CONFIG = YAML.load_file("config/deploy.yml")
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30
    UNSUPPORTED = ["gcr.io", "ghcr.io", "quay.io"].freeze
    UNSUPPORTED = ["gcr.io", "ghcr.io"].freeze

    # These suffixes are just different versions of the same image.
    # When it comes to versioning, we only care about the version number.
    def normalize_tag(tag)
    tag.chomp("-ubuntu").chomp("-alpine").chomp("-bookworm").chomp("-bullseye")
    tag.sub(/^v|-ubuntu.*|-alpine.*|-bookworm.*|-bullseye.*/, "")
    end

    ACCESSORIES.each_value do |config|
    image, tag = config["image"].split(":")
    def scrape_tags(repository, service)
    url, tags_under_key = case service
    when "dockerhub"
    [URI("https://hub.docker.com/v2/repositories/#{repository}/tags?page_size=#{MAX_RESULTS}"), "results"]
    when "quay"
    [URI("https://quay.io/api/v1/repository/#{repository}/tag/"), "tags"]
    end

    next puts "😔 Skipping #{image}, not supported...yet\n\n" if image.start_with?(*UNSUPPORTED)
    response = Net::HTTP.get_response(url)

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images
    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)

    namespace, repository = image.include?("/") ? image.split("/") : ["library", image]
    data[tags_under_key].map { |tag| tag["name"] } # rubocop:disable Rails/Pluck
    else
    puts "💣 Error: #{response.code}\n\n"
    end
    end

    puts "👀 Checking image updates for #{image} (Current version: #{tag})"
    ACCESSORIES.each_value do |config| # rubocop:disable Metrics/BlockLength
    image, current_tag = config["image"].split(":")

    url = URI("https://hub.docker.com/v2/repositories/#{namespace}/#{repository}/tags?page_size=#{MAX_RESULTS}")
    next puts "⏭️ Skipping #{image}, no tag specified\n\n" if current_tag.nil?

    response = Net::HTTP.get_response(url)
    unsupported_message = <<~MESSAGE
    😓 Skipping #{image}, not supported...yet
    You might want to manually check for updates at https://#{image}
    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)
    MESSAGE

    next puts unsupported_message if image.start_with?(*UNSUPPORTED)

    repository = image.sub(%r{lscr.io/|quay.io/}, "").then do |repo|
    repo.include?("/") ? repo.split("/") : ["library", repo]
    end.join("/")

    puts "👀 Checking image updates for #{repository} (Current version: #{current_tag})"

    tags = case image
    when /quay.io/
    scrape_tags(repository, "quay")
    else
    scrape_tags(repository, "dockerhub")
    end
    local_tag = normalize_tag(current_tag)

    tags.each do |tag|
    upstream_tag = normalize_tag(tag)

    local_tag = normalize_tag(tag)
    data["results"].each do |result|
    upstream_tag = normalize_tag(result["name"])
    next unless Gem::Version.correct?(upstream_tag)

    if Gem::Version.new(local_tag) < Gem::Version.new(upstream_tag) # rubocop:disable Style/IfUnlessModifier
    break puts " 🎉 New version available: #{result['name']}"
    end
    rescue ArgumentError # Skip, `Gem::Version.new` fails for "latest" tag, for example
    next
    if Gem::Version.new(local_tag) < Gem::Version.new(upstream_tag) # rubocop:disable Style/IfUnlessModifier
    break puts " 🚀 New version available: #{tag}"
    end
    puts "\n"
    else
    puts "💣 Error: #{response.code}\n\n"
    end

    puts "\n"
    end
  3. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -11,6 +11,7 @@
    CONFIG = YAML.load_file("config/deploy.yml")
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30
    UNSUPPORTED = ["gcr.io", "ghcr.io", "quay.io"].freeze

    # These suffixes are just different versions of the same image.
    # When it comes to versioning, we only care about the version number.
    @@ -21,7 +22,7 @@ def normalize_tag(tag)
    ACCESSORIES.each_value do |config|
    image, tag = config["image"].split(":")

    next puts "😔 Skipping #{image}, not supported...yet\n\n" if image.start_with?("gcr.io", "ghcr.io", "quay.io")
    next puts "😔 Skipping #{image}, not supported...yet\n\n" if image.start_with?(*UNSUPPORTED)

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images

    @@ -43,7 +44,7 @@ def normalize_tag(tag)
    if Gem::Version.new(local_tag) < Gem::Version.new(upstream_tag) # rubocop:disable Style/IfUnlessModifier
    break puts " 🎉 New version available: #{result['name']}"
    end
    rescue ArgumentError # Skip, `Gem::Version.new` fails for "latest" tag for example
    rescue ArgumentError # Skip, `Gem::Version.new` fails for "latest" tag, for example
    next
    end
    puts "\n"
  4. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 12 additions and 7 deletions.
    19 changes: 12 additions & 7 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -12,8 +12,14 @@
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30

    ACCESSORIES.each_value do |configs|
    image, tag = configs["image"].split(":")
    # These suffixes are just different versions of the same image.
    # When it comes to versioning, we only care about the version number.
    def normalize_tag(tag)
    tag.chomp("-ubuntu").chomp("-alpine").chomp("-bookworm").chomp("-bullseye")
    end

    ACCESSORIES.each_value do |config|
    image, tag = config["image"].split(":")

    next puts "😔 Skipping #{image}, not supported...yet\n\n" if image.start_with?("gcr.io", "ghcr.io", "quay.io")

    @@ -30,15 +36,14 @@
    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)

    local_tag = normalize_tag(tag)
    data["results"].each do |result|
    if Gem::Version.new(tag) < Gem::Version.new(result["name"])
    # when tag is `11.2.0-ubuntu`, Gem::Version.new("11.2.0-ubuntu") < Gem::Version.new("11.2.0") and it's not a new version
    next if tag.start_with?(result["name"])
    upstream_tag = normalize_tag(result["name"])

    if Gem::Version.new(local_tag) < Gem::Version.new(upstream_tag) # rubocop:disable Style/IfUnlessModifier
    break puts " 🎉 New version available: #{result['name']}"
    end
    rescue StandardError
    # Skip, `Gem::Version.new` fails for "latest" tag for example
    rescue ArgumentError # Skip, `Gem::Version.new` fails for "latest" tag for example
    next
    end
    puts "\n"
  5. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -19,11 +19,11 @@

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images

    namespace, image = image.include?("/") ? image.split("/") : ["library", image]
    namespace, repository = image.include?("/") ? image.split("/") : ["library", image]

    puts "👀 Checking image updates for #{image} (Current version: #{tag})"

    url = URI("https://hub.docker.com/v2/repositories/#{namespace}/#{image}/tags?page_size=#{MAX_RESULTS}")
    url = URI("https://hub.docker.com/v2/repositories/#{namespace}/#{repository}/tags?page_size=#{MAX_RESULTS}")

    response = Net::HTTP.get_response(url)

  6. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 13 additions and 17 deletions.
    30 changes: 13 additions & 17 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    #!/usr/bin/env ruby
    # frozen_string_literal: true

    # lives in .kamal/update

    @@ -11,20 +12,18 @@
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30

    ACCESSORIES.each do |name, configs|
    ACCESSORIES.each_value do |configs|
    image, tag = configs["image"].split(":")

    if image.start_with?("gcr.io")
    puts "Skipping #{image}, not supported yet"
    next puts "😔 Skipping #{image}, not supported...yet\n\n" if image.start_with?("gcr.io", "ghcr.io", "quay.io")

    next
    end
    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images

    puts "Checking image updates for #{image} (Current version: #{tag})"
    namespace, image = image.include?("/") ? image.split("/") : ["library", image]

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images
    puts "👀 Checking image updates for #{image} (Current version: #{tag})"

    url = URI("https://hub.docker.com/v2/repositories/#{image}/tags?page_size=#{MAX_RESULTS}")
    url = URI("https://hub.docker.com/v2/repositories/#{namespace}/#{image}/tags?page_size=#{MAX_RESULTS}")

    response = Net::HTTP.get_response(url)

    @@ -33,20 +32,17 @@

    data["results"].each do |result|
    if Gem::Version.new(tag) < Gem::Version.new(result["name"])
    if tag.start_with?(result["name"])
    # when tag is `11.2.0-ubuntu`, Gem::Version.new("11.2.0-ubuntu") < Gem::Version.new("11.2.0") and it's not a new version
    next
    end

    puts " ~> New version available: #{result["name"]}"
    # when tag is `11.2.0-ubuntu`, Gem::Version.new("11.2.0-ubuntu") < Gem::Version.new("11.2.0") and it's not a new version
    next if tag.start_with?(result["name"])

    break
    break puts " 🎉 New version available: #{result['name']}"
    end
    rescue
    rescue StandardError
    # Skip, `Gem::Version.new` fails for "latest" tag for example
    next
    end
    puts "\n"
    else
    puts "Error: #{response.code}"
    puts "💣 Error: #{response.code}\n\n"
    end
    end
  7. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion update.rb
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@
    break
    end
    rescue
    # Skip
    # Skip, `Gem::Version.new` fails for "latest" tag for example
    next
    end
    else
  8. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,7 @@

    CONFIG = YAML.load_file("config/deploy.yml")
    ACCESSORIES = CONFIG["accessories"]
    MAX_RESULTS = 30

    ACCESSORIES.each do |name, configs|
    image, tag = configs["image"].split(":")
    @@ -23,15 +24,14 @@

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images

    url = URI("https://hub.docker.com/v2/repositories/#{image}/tags")
    url = URI("https://hub.docker.com/v2/repositories/#{image}/tags?page_size=#{MAX_RESULTS}")

    response = Net::HTTP.get_response(url)

    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)

    # Take only 20 results, it should be enough
    data["results"].take(20).each do |result|
    data["results"].each do |result|
    if Gem::Version.new(tag) < Gem::Version.new(result["name"])
    if tag.start_with?(result["name"])
    # when tag is `11.2.0-ubuntu`, Gem::Version.new("11.2.0-ubuntu") < Gem::Version.new("11.2.0") and it's not a new version
  9. luizkowalski revised this gist Aug 29, 2024. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    #!/usr/bin/env ruby

    # lives in .kamal/update

    require "json"
    require "net/http"
    require "uri"
  10. luizkowalski created this gist Aug 29, 2024.
    50 changes: 50 additions & 0 deletions update.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    #!/usr/bin/env ruby

    require "json"
    require "net/http"
    require "uri"
    require "yaml"

    CONFIG = YAML.load_file("config/deploy.yml")
    ACCESSORIES = CONFIG["accessories"]

    ACCESSORIES.each do |name, configs|
    image, tag = configs["image"].split(":")

    if image.start_with?("gcr.io")
    puts "Skipping #{image}, not supported yet"

    next
    end

    puts "Checking image updates for #{image} (Current version: #{tag})"

    image = image.gsub("lscr.io/", "") # Remove `lscr.io/` from linuxserver images

    url = URI("https://hub.docker.com/v2/repositories/#{image}/tags")

    response = Net::HTTP.get_response(url)

    if response.is_a?(Net::HTTPSuccess)
    data = JSON.parse(response.body)

    # Take only 20 results, it should be enough
    data["results"].take(20).each do |result|
    if Gem::Version.new(tag) < Gem::Version.new(result["name"])
    if tag.start_with?(result["name"])
    # when tag is `11.2.0-ubuntu`, Gem::Version.new("11.2.0-ubuntu") < Gem::Version.new("11.2.0") and it's not a new version
    next
    end

    puts " ~> New version available: #{result["name"]}"

    break
    end
    rescue
    # Skip
    next
    end
    else
    puts "Error: #{response.code}"
    end
    end