slackbuilder/lib/up2date.rb

128 lines
3.4 KiB
Ruby
Raw Normal View History

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
require 'net/http'
require 'json'
require_relative '../config/config'
2023-05-29 22:17:35 +02:00
require 'term/ansicolor'
module SlackBuilder
2023-05-29 22:17:35 +02:00
extend Term::ANSIColor
2023-05-24 12:56:55 +02:00
# Remote repository for a single package.
class Repository
# Request the latest tag in the given repository.
def latest
raise NotImplementedError
end
end
# Reads the list fo tags from the GitHub API.
2023-05-24 12:56:55 +02:00
class GitHub < Repository
GITHUB_QUERY = <<~GQL
query ($name: String!, $owner: String!) {
repository(name: $name, owner: $owner) {
refs(last: 10, refPrefix: "refs/tags/", orderBy: { field: TAG_COMMIT_DATE, direction: ASC }) {
2023-05-24 12:56:55 +02:00
nodes {
id,
name
}
}
}
}
2023-05-24 12:56:55 +02:00
GQL
private_constant :GITHUB_QUERY
2023-06-28 23:47:21 +02:00
def initialize(owner, name, version_transform = ->(v) { v.delete_prefix 'v' })
2023-05-24 12:56:55 +02:00
super()
@owner = owner
@name = name
@version_transform = version_transform
2023-05-24 12:56:55 +02:00
end
def latest
post_data = {
'query' => GITHUB_QUERY,
'variables' => { 'name' => @name, 'owner' => @owner }
}
uri = URI('https://api.github.com/graphql')
response = Net::HTTP.post uri, post_data.to_json, {
'content-type' => 'application/json',
'authorization' => "Bearer #{CONFIG[:gh_token]}"
}
filter_versions_from_response JSON.parse(response.body)
end
private
def filter_versions_from_response(response)
response['data']['repository']['refs']['nodes']
.map { |node| @version_transform.call node['name'] }
.compact
.last
2023-05-24 12:56:55 +02:00
end
end
# Request the latest version from the packagist API.
2023-05-24 12:56:55 +02:00
class Packagist < Repository
def initialize(vendor, name)
super()
@vendor = vendor
@name = name
end
def latest
full_name = [@vendor, @name].join '/'
uri = URI "https://repo.packagist.org/p2/#{full_name}.json"
response = Net::HTTP.get uri, {
'content-type' => 'application/json'
}
JSON.parse(response)['packages'][full_name].first['version']
end
end
# Reads a remote LATEST file.
class LatestText < Repository
def initialize(latest_url)
super()
@latest_url = URI latest_url
end
def latest
response = Net::HTTP.get @latest_url, {
'content-type' => 'text/plain'
}
response.strip
end
end
2023-05-29 22:17:35 +02:00
module_function
# Checks if there is a new version for the package and returns the latest
# version if an update is available, otherwise returns nil.
def check_for_latest(package_name, repository)
package = find_package_info package_name
2023-05-24 12:56:55 +02:00
latest_version = repository.latest
if package.version == latest_version
2023-05-29 22:17:35 +02:00
puts green "#{package_name} is up to date (Version #{package.version})."
nil
2023-05-24 12:56:55 +02:00
else
2023-05-29 22:17:35 +02:00
puts red "#{package_name}: Current version is #{package.version}, #{latest_version} is available."
latest_version
2023-05-24 12:56:55 +02:00
end
end
2023-05-29 22:17:35 +02:00
private_class_method def find_package_info(package_name)
package_path = Pathname.new Dir.glob("#{CONFIG[:repository]}/*/#{package_name}").first
package_category = package_path.dirname.basename.to_s
Package.parse("#{package_category}/#{package_name}", File.read("#{package_path}/#{package_name}.info"))
end
end