2020-12-31 22:55:59 +00:00
|
|
|
# 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)
|
2021-01-02 20:29:57 +00:00
|
|
|
old_content = File.read(full_path) if File.readable?(full_path)
|
2020-12-31 22:55:59 +00:00
|
|
|
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
|