VIVO-272 Create scripts to build a release from GitHub.

This commit is contained in:
j2blake 2013-09-02 11:10:13 -04:00
parent 1994ab03a1
commit f72913a2f1
8 changed files with 755 additions and 0 deletions

View file

@ -0,0 +1,141 @@
=begin
--------------------------------------------------------------------------------
Check for the required parameters of base directory, username, email address,
revision label and candidate label.
Offer to run the licenser to be sure that we are ready to go.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# ------------------------------------------------------------------------------------
# Runs the licenser against both VIVO and Vitro, and shows the results.
# ------------------------------------------------------------------------------------
#
class LicenserCaller
def call_licenser(property_file)
properties = PropertyFileReader.read(property_file)
l = Licenser.new(properties)
l.process
l.report(properties)
return l.success?
end
def initialize()
require "#{Settings.vitro_path}/utilities/licenser/licenser"
require "#{Settings.vitro_path}/utilities/licenser/property_file_reader"
puts "Scanning VIVO..."
vivo_success = call_licenser("#{Settings.vivo_path}/config/licenser/licenser.properties")
puts "Scanning Vitro..."
vitro_success = call_licenser("#{Settings.vitro_path}/webapp/config/licenser/licenser.properties")
if vivo_success && vitro_success
puts "Licenser was successful"
else
puts "Licenser found problems"
end
end
end
#
# Show the current value of the setting, ask for a replacement value, validate it, and set it.
#
def do_setting(getter, validator, setter, label, format="a string")
v1 = getter.call
currently = v1.empty? ? "Currently not set" : "Currently '#{v1}'"
v2 = prompt "#{label}?\n(#{format})\n(#{currently})"
v2 = v1 if v2.empty?
v2 = validator.call(v2)
if v2.empty?
raise InputException.new("Can't run without #{label}")
elsif v1 == v2
puts "Keeping #{label} as '#{v2}'"
puts
else
puts "Setting #{label} to '#{v2}'"
setter.call(v2)
puts
end
v2
end
def get_base_directory()
do_setting(
Settings.method(:base_directory),
Settings.method(:confirm_base_directory),
Settings.method(:base_directory=),
"Git base directory",
"holds Vitro and VIVO repositories")
end
def get_user_name()
do_setting(
Settings.method(:username),
Settings.method(:confirm_username),
Settings.method(:username=),
"Git user.name")
end
def get_email()
do_setting(
Settings.method(:email),
Settings.method(:confirm_email),
Settings.method(:email=),
"Git user.email")
end
def get_release_label()
do_setting(
Settings.method(:release_label),
Settings.method(:confirm_release_label),
Settings.method(:release_label=),
"Release label",
"like '3.2' or '3.2.1'")
end
def get_candidate_label()
do_setting(
Settings.method(:candidate_label),
Settings.method(:confirm_candidate_label),
Settings.method(:candidate_label=),
"Release candidate label",
"like 'rc1' or 'tc3' or 'final'")
end
def run_licenser()
puts "It's a good idea to check the licenses before proceeding."
yn = prompt "Ready to run the licenser? (y/n)"
if (yn.downcase == 'y')
LicenserCaller.new()
else
puts "OK - forget it."
end
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
get_base_directory()
get_user_name()
get_email()
get_release_label()
get_candidate_label()
run_licenser()
rescue BadState
puts
puts "#{$!.message} - Aborting."
puts
end

View file

@ -0,0 +1,59 @@
=begin
--------------------------------------------------------------------------------
Get the branch name.
If either repository already contains the branch, complain.
Otherwise, pull develop to the latest commit and create the branches. Don't push.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Create a branch by this name in this repository.
#
def create_branch(dir, branch)
Dir.chdir(dir) do |path|
approve_and_execute([
"git checkout develop",
"git pull",
"git checkout -b #{branch}"
], "in #{path}")
end
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
branch = Settings.branch_name
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
raise BadState.new("Branch #{branch} already exists in VIVO.") if branch_exists?(vivo_path, branch)
raise BadState.new("Branch #{branch} already exists in Vitro.") if branch_exists?(vitro_path, branch)
puts
yn = prompt("OK to create branches named '#{branch}' (y/n)")
if yn.downcase == 'y'
puts
puts "Creating branches"
create_branch(vivo_path, branch)
create_branch(vitro_path, branch)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,70 @@
=begin
--------------------------------------------------------------------------------
Get the branch name and the tag name.
If either repository doesn't contain the branch, complain.
If either repository already contains the tag, complain.
Otherwise, Checkout the branch, pull the branch to the latest commit (if it is
tracking a remote branch) and create the tag. Don't push.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Create a tag by this name in this repository.
#
def create_tag(dir, branch, tag, message)
Dir.chdir(dir) do |path|
cmds = ["git checkout #{branch}",
"git pull",
"git tag -a #{tag} -m '#{message}'"
]
cmds.delete_at(1) unless is_remote_branch?(branch)
approve_and_execute(cmds, "in #{path}")
end
end
def is_remote_branch?(branch)
! `git branch --list -a origin/#{branch}`.strip.empty?
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
branch = Settings.branch_name
tag = Settings.tag_name
message = Settings.tag_message
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
raise BadState.new("Branch #{branch} doesn't exist in VIVO.") unless branch_exists?(vivo_path, branch)
raise BadState.new("Branch #{branch} doesn't exist in Vitro.") unless branch_exists?(vitro_path, branch)
raise BadState.new("Tag #{tag} already exists in VIVO.") if tag_exists?(vivo_path, tag)
raise BadState.new("Tag #{tag} already exists in Vitro.") if tag_exists?(vitro_path, tag)
puts
yn = prompt("OK to create tags named '#{tag}' '#{message}' (y/n)")
if yn.downcase == 'y'
puts
puts "Creating tags"
create_tag(vivo_path, branch, tag, message)
create_tag(vitro_path, branch, tag, message)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,69 @@
=begin
--------------------------------------------------------------------------------
Get the tag name.
If either repository doesn't contain the tag, complain.
Otherwise, checkout the tag, copy the files to an appropriate area.
The files are specified so hidden files will not be copied, but this only works
at the top levels. So the .git directories are omitted, as well as some Eclipse
artifacts and Mac OS artifacts. However, this only works at the top levels.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Get the VIVO files and the Vitro files, and remove the .git directories.
#
def export_files(vivo_path, vitro_path, tag, export_dir)
approve_and_execute([
"rm -Rf #{export_dir}/..",
"mkdir -pv #{export_dir}",
"cp -R #{vivo_path}/* #{export_dir}",
"mkdir -pv #{export_dir}/vitro-core",
"cp -R #{vitro_path}/* #{export_dir}/vitro-core",
])
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
tag = Settings.tag_name
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
export_dir = Settings.export_dir
raise BadState.new("Tag #{tag} doesn't exist in VIVO.") unless tag_exists?(vivo_path, tag)
raise BadState.new("Tag #{tag} doesn't exist in Vitro.") unless tag_exists?(vitro_path, tag)
if File.directory?(export_dir)
p = "OK to overwrite export area at #{export_dir} ? (y/n)"
else
p = "OK to create export area at #{export_dir} ? (y/n)"
end
puts
yn = prompt(p)
if yn.downcase == 'y'
puts
puts "Building export area"
export_files(vivo_path, vitro_path, tag, export_dir)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,70 @@
=begin
--------------------------------------------------------------------------------
Figure the revision info and store it in the export directory, for both VIVO
and Vitro.
If the tags don't exist in either repository, or if the export directory is not
populated, complain.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Get the revision information from Git and store it in the export directory.
#
def create_revision_info(git_path, info_file_path, tag)
Dir.chdir(git_path) do |path|
commit = `git show-ref --tags --hash=7 #{tag}`.strip
puts "Writing '#{tag} ~ #{commit}' to #{info_file_path}"
File.open(info_file_path, "w") do |f|
f.puts tag
f.puts commit
end
end
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
tag = Settings.tag_name
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
export_dir = Settings.export_dir
vivo_revision_info_path = Settings.vivo_revision_info_path
vitro_revision_info_path = Settings.vitro_revision_info_path
raise BadState.new("Tag #{tag} doesn't exist in VIVO.") unless tag_exists?(vivo_path, tag)
raise BadState.new("Tag #{tag} doesn't exist in Vitro.") unless tag_exists?(vitro_path, tag)
raise BadState.new("Files have not been exported to #{export_dir}") unless File.directory?(export_dir)
if File.exist?(vivo_revision_info_path) || File.exist?(vitro_revision_info_path)
p = "OK to overwrite revision_info at these paths? \n #{vivo_revision_info_path} \n #{vitro_revision_info_path} ? (y/n)"
else
p = "OK to write revision_info at these paths? \n #{vivo_revision_info_path} \n #{vitro_revision_info_path} ? (y/n)"
end
puts
yn = prompt(p)
if yn.downcase == 'y'
puts
puts "Building revision info"
create_revision_info(vivo_path, vivo_revision_info_path, tag)
create_revision_info(vitro_path, vitro_revision_info_path, tag)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,73 @@
=begin
--------------------------------------------------------------------------------
Create TAR and ZIP files for both VIVO and Vitro.
Complain if the files have not been exported, or the revision info doesn't exist.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Zip up the VIVO distribution. Extract the Vitro distribution and zip that.
#
def create_distribution_files(export_dir, vivo_filename, vitro_filename)
export_parent_dir = File.dirname(export_dir)
Dir.chdir(export_parent_dir) do |path|
cmds = [
"cp -r #{vivo_filename}/vitro-core #{vitro_filename}",
"zip -rq #{vivo_filename}.zip #{vivo_filename}",
"tar -czf #{vivo_filename}.tar.gz #{vivo_filename}",
"zip -rq #{vitro_filename}.zip #{vitro_filename}",
"tar -czf #{vitro_filename}.tar.gz #{vitro_filename}"
]
cmds.insert(0, "rm -r #{vitro_filename}") if File.exist?(vitro_filename)
approve_and_execute(cmds)
end
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
tag = Settings.tag_name
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
export_dir = Settings.export_dir
vivo_revision_info_path = Settings.vivo_revision_info_path
vitro_revision_info_path = Settings.vitro_revision_info_path
vivo_filename = Settings.vivo_distribution_filename
vitro_filename = Settings.vitro_distribution_filename
raise BadState.new("Files have not been exported to #{export_dir}") unless File.directory?(export_dir)
raise BadState.new("Revision information file does not exist at #{vivo_revision_info_path}") unless File.exist?(vivo_revision_info_path)
raise BadState.new("Revision information file does not exist at #{vitro_revision_info_path}") unless File.exist?(vitro_revision_info_path)
if File.exist?(vivo_revision_info_path) || File.exist?(vitro_revision_info_path)
p = "OK to overwrite revision_info at these paths? \n #{vivo_revision_info_path} \n #{vitro_revision_info_path} ? (y/n)"
else
p = "OK to write revision_info at these paths? \n #{vivo_revision_info_path} \n #{vitro_revision_info_path} ? (y/n)"
end
puts
yn = prompt("OK to create distribution files in #{export_dir} ? (y/n)")
if yn.downcase == 'y'
puts
puts "Creating distribution files"
create_distribution_files(export_dir, vivo_filename, vitro_filename)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,60 @@
=begin
--------------------------------------------------------------------------------
Merge the new tags into the master branches.
This will only work if the tag is present, and if the release candidate is "final".
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
$: << File.dirname(File.expand_path(__FILE__))
require '_common'
#
# Merge the tag to the master branch.
#
def merge_tag_to_master(tag, repo_path)
Dir.chdir(repo_path) do |path|
approve_and_execute([
"git checkout master",
"git merge #{tag}"
])
end
end
#
# ------------------------------------------------------------------------------------
# Main method
# ------------------------------------------------------------------------------------
#
begin
candidate_label = Settings.confirm_candidate_label(Settings.candidate_label)
tag = Settings.tag_name
vivo_path = Settings.vivo_path
vitro_path = Settings.vitro_path
raise BadState.new("Only the final release gets merged to the master branch.") unless candidate_label == "final"
raise BadState.new("Tag #{tag} doesn't exist in VIVO.") unless tag_exists?(vivo_path, tag)
raise BadState.new("Tag #{tag} doesn't exist in Vitro.") unless tag_exists?(vitro_path, tag)
raise BadState.new("Tag has already been merged to master branch in VIVO." if tag_commit(tag, vivo_path) == master_commit(vivo_path)
raise BadState.new("Tag has already been merged to master branch in Vitro." if tag_commit(tag, vitro_path) == master_commit(vitro_path)
puts
yn = prompt("OK to merge the #{tag} tags to the master branches? (y/n)")
if yn.downcase == 'y'
puts
puts "Merging tags"
merge_tag_to_master(tag, vivo_path)
merge_tag_to_master(tag, vitro_path)
puts
else
puts
puts "OK - forget it."
puts
end
rescue BadState
puts "#{$!.message} - Aborting."
end

View file

@ -0,0 +1,213 @@
=begin
--------------------------------------------------------------------------------
Methods and classes used by the scripts.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
=end
#
# ------------------------------------------------------------------------------------
# This exception class says that we aren't happy with the state of things.
# ------------------------------------------------------------------------------------
#
class BadState < Exception
end
#
# ------------------------------------------------------------------------------------
# A class with methods for handling the settings.
# ------------------------------------------------------------------------------------
#
class Settings
def self.base_directory
`git config --get --global vivo.release.basedirectory`.strip
end
def self.base_directory=(dir)
`git config --global vivo.release.basedirectory #{dir}`
end
def self.confirm_base_directory(path)
expanded = File.expand_path(path)
vivo_git = File.expand_path("VIVO/.git", expanded)
vitro_git = File.expand_path("Vitro/.git", expanded)
raise BadState.new("#{expanded} is not a directory") unless File.directory?(expanded)
raise BadState.new("#{expanded} doesn't contain a VIVO repository") unless File.directory?(vivo_git)
raise BadState.new("#{expanded} doesn't contain a Vitro repository") unless File.directory?(vitro_git)
expanded
end
def self.username
`git config --get --global user.name`.strip
end
def self.username=(name)
`git config --global user.name #{name}`
end
def self.confirm_username(name)
# any string will do.
name
end
def self.email
`git config --get --global user.email`.strip
end
def self.email=(address)
`git config --global user.email #{address}`
end
def self.confirm_email(address)
# any string will do.
address
end
def self.release_label
`git config --get --global vivo.releaselabel`.strip
end
def self.release_label=(label)
`git config --global vivo.releaselabel #{label}`
end
def self.confirm_release_label(label)
raise BadState.new("Incorrect format for release label - '#{label}'") unless label =~ /^\d\.\d(\.\d)?$/
label
end
def self.candidate_label
`git config --get --global vivo.candidatelabel`.strip
end
def self.candidate_label=(label)
`git config --global vivo.candidatelabel #{label}`
end
def self.confirm_candidate_label(label)
raise BadState.new("Incorrect format for candidate label - '#{label}'") unless label =~ /^(rc\d+|tc\d+|final)$/
label
end
#
# Values derived from the settings.
#
# The name of the maintenance branch. Looks like "maint-rel-4.2" even for releases like "4.2.1"
def self.branch_name
label = Settings.confirm_release_label(Settings.release_label)
major_release = label[0..2]
"maint-rel-#{major_release}"
end
# The name of the Git tag. Looks like "rel-1.9-tc2" or "rel-1.9" (for final)
def self.tag_name
release_label = Settings.confirm_release_label(Settings.release_label)
label = Settings.confirm_candidate_label(Settings.candidate_label)
suffix = label == "final" ? "" : "-#{label}"
"rel-#{release_label}#{suffix}"
end
# The message for the Git tag. Looks like "Release 1.9 rc5 tag"
def self.tag_message
release_label = Settings.confirm_release_label(Settings.release_label)
candidate_label = Settings.confirm_candidate_label(Settings.candidate_label)
"Release #{release_label} #{candidate_label} tag"
end
# Where is the local VIVO repository? Looks like "/Users/jeb228/git/VIVO"
def self.vivo_path
base_directory = Settings.confirm_base_directory(Settings.base_directory)
File.expand_path("VIVO", base_directory)
end
# Where is the local Vitro repository? Looks like "/Users/jeb228/git/Vitro"
def self.vitro_path
base_directory = Settings.confirm_base_directory(Settings.base_directory)
File.expand_path("Vitro", base_directory)
end
# Where will the distribution files be created? Looks like "/Users/jeb228/git/release_4.9/tc5/vivo-rel-4.9-tc5"
def self.export_dir
base_directory = Settings.confirm_base_directory(Settings.base_directory)
release_label = Settings.confirm_release_label(Settings.release_label)
candidate_label = Settings.confirm_candidate_label(Settings.candidate_label)
tag_name = Settings.tag_name
File.expand_path("release_#{release_label}/#{candidate_label}/vivo-#{tag_name}", base_directory)
end
# Where to store the file for revision info in VIVO
def self.vivo_revision_info_path
File.expand_path("revisionInfo", Settings.export_dir)
end
# Where to store the file for revision info in VIVO
def self.vitro_revision_info_path
File.expand_path("vitro-core/revisionInfo", Settings.export_dir)
end
# Looks like "vivo-rel-4.9-tc3" or "vivo-rel-4.9" for final
def self.vivo_distribution_filename
"vivo-#{Settings.tag_name}"
end
# Looks like "vitro-rel-4.9-tc3" or "vitro-rel-4.9" for final
def self.vitro_distribution_filename
"vitro-#{Settings.tag_name}"
end
end
#
# ------------------------------------------------------------------------------------
# General-purpose methods.
# ------------------------------------------------------------------------------------
#
def prompt(p)
print("#{p} ")
gets.strip
end
def echo_command(c)
puts ">>>>>> #{c}"
`#{c}`
end
def approve_and_execute(cmds, prompt="")
if prompt.empty?
puts "Execute these commands?"
else
puts "Execute these commands? (#{prompt})"
end
puts ">>>>> #{cmds.join("\n>>>>> ")}"
yn = prompt "(y/n)"
raise BadState.new("OK") if (yn.downcase != 'y')
cmds.each do |cmd|
puts ">>>>> #{cmd}"
puts `#{cmd}`
raise BadState.new("Command failed: code #{$?.exitstatus}") unless $?.success?
end
puts
end
def branch_exists?(dir, branch)
Dir.chdir(dir) do |path|
! `git branch --list #{branch}`.strip.empty?
end
end
def tag_exists?(dir, tag)
Dir.chdir(dir) do |path|
!`git tag --list #{tag}`.strip.empty?
end
end