google-api-ruby-client/google-api-client/lib/google/apis/generator/updater.rb

140 lines
5.8 KiB
Ruby

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "gems"
module Google
module Apis
class Generator
# Matches generated files against current files and decides what to update
# @private
class Updater
def initialize
@gems_client = nil
@current_rubygems_versions = {}
end
def analyze(base_dir, generator_result)
modified_files = {}
version_content = changelog_content = nil
generator_result.files.each do |path, content|
full_path = File.join(base_dir, path)
old_content = File.binread(full_path) if File.readable?(full_path)
if path == generator_result.version_path
version_content = old_content || content
elsif path == generator_result.changelog_path
changelog_content = old_content || content
else
modified_files[path] = content unless content == old_content
end
end
unless modified_files.empty?
desired_gem_version = next_rubygems_version(generator_result.gem_name)
version_content, generator_version_change, revision_change =
update_version_content(version_content, desired_gem_version, generator_result.revision)
changelog_content = update_changelog_content(changelog_content, desired_gem_version, generator_version_change, revision_change)
modified_files[generator_result.version_path] = version_content
modified_files[generator_result.changelog_path] = changelog_content
end
modified_files
end
# @private
def gems_client
@gems_client ||= Gems::Client.new
end
# @private
def current_rubygems_version(gem_name)
@current_rubygems_versions[gem_name] ||= begin
gems_client.info(gem_name)["version"]
rescue Gems::NotFound
"0.0.0"
end
end
# @private
def next_rubygems_version(gem_name)
major, minor = current_rubygems_version(gem_name).split(".")
"#{major.to_i}.#{minor.to_i + 1}.0"
end
# @private
def update_version_content(content, desired_gem_version, new_revision)
generator_version_change = revision_change = nil
modified_content = content.dup
modified_content.sub!(/GEM_VERSION = "([\w\.]*)"/) do |*|
"GEM_VERSION = \"#{desired_gem_version}\""
end or raise "gem_version.rb is missing GEM_VERSION"
modified_content.sub!(/GENERATOR_VERSION = "([\w\.]*)"/) do |*|
generator_version_change = Generator::VERSION unless Regexp.last_match[1] == Generator::VERSION
"GENERATOR_VERSION = \"#{Generator::VERSION}\""
end or raise "gem_version.rb is missing GENERATOR_VERSION"
modified_content.sub!(/REVISION = "([\w\.]*)"/) do |*|
revision_change = new_revision unless Regexp.last_match[1] == new_revision
"REVISION = \"#{new_revision}\""
end or raise "gem_version.rb is missing REVISION"
[modified_content, generator_version_change, revision_change]
end
# @private
def update_changelog_content(content, desired_gem_version, generator_version_change, revision_change)
lines = parse_existing_changelog_entry(content, desired_gem_version)
modify_changelog_lines(lines, generator_version_change, revision_change)
entry = assemble_changelog_entry(lines, desired_gem_version)
replace_changelog_entry(content, desired_gem_version, entry)
end
# @private
def parse_existing_changelog_entry(content, desired_gem_version)
quoted_gem_version = Regexp.quote(desired_gem_version)
match = /\n+### v#{quoted_gem_version} \([\d-]+\)\n+((?:[^#][^\n]*\n+)*)(?=#|$)/.match content
return [] unless match
match[1].split("\n")
end
# @private
def modify_changelog_lines(lines, generator_version_change, revision_change)
if generator_version_change
lines.reject! { |line| line =~ /^\* Regenerated using generator version \d[\w\.]+/ }
lines.unshift("* Regenerated using generator version #{generator_version_change}")
end
if revision_change
lines.reject! { |line| line =~ /^\* Regenerated from discovery document revision \d+/ }
lines.unshift("* Regenerated from discovery document revision #{revision_change}")
end
lines << "* Unspecified changes" if lines.empty?
end
# @private
def assemble_changelog_entry(lines, desired_gem_version)
entry_lines = lines.join("\n")
date = Time.now.strftime("%Y-%m-%d")
"\n\n### v#{desired_gem_version} (#{date})\n\n#{entry_lines}\n\n"
end
# @private
def replace_changelog_entry(content, desired_gem_version, entry)
quoted_gem_version = Regexp.quote(desired_gem_version)
modified_content = content.dup
modified_content.sub!(/\n+### v#{quoted_gem_version} \([\d-]+\)\n+(?:[^#][^\n]*\n+)*(?=#|$)/, entry) or
modified_content.sub!(/^(\n*# [^\n]+)\n+(?=#|$)/, "\\1#{entry}") or
raise "CHANGELOG doesn't seem to have the expected header"
modified_content
end
end
end
end
end