blob: 657eaaeecc1ec2b047b860ff38bdcadb90e2d4ac [file]
# -*- ruby -*-
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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 "digest/sha2"
require "json"
require "tmpdir"
require_relative "helper"
project_label = "Apache Arrow Flight SQL adapter for PostgreSQL"
version = Helper.detect_version
archive_base_name = "apache-arrow-flight-sql-postgresql-#{version}"
archive_name = "#{archive_base_name}.tar.gz"
file archive_name do
sh("git",
"archive",
"HEAD",
"--output", archive_name,
"--prefix", "#{archive_base_name}/")
end
desc "Create #{archive_name}"
task :dist => archive_name
def build_doc(output_directory, release: nil, for_publish: false)
env = {}
env["RELEASE"] = release if release
sh(env,
"sphinx-build",
"-b", "html",
"-j", "auto",
"doc/source",
output_directory)
if for_publish
rm_f("#{output_directory}/.buildinfo")
rm_rf("#{output_directory}/.doctrees")
end
end
namespace :doc do
desc "Build HTML documentation"
task :html do
build_doc("doc/build")
end
desc "Publish HTML documentation"
task :publish do
site = ENV["ASF_SITE"] || "site"
asf_yaml = File.expand_path(".asf.yaml")
index_html = File.expand_path("doc/index.html")
Dir.mktmpdir do |tmp|
is_release = (ENV["GITHUB_REF_TYPE"] == "tag")
if is_release
tag = ENV["GITHUB_REF_NAME"]
new_version = tag.gsub(/-rc\d+\z/, "")
is_release_candiate = (tag != new_version)
new_doc = "#{tmp}/new"
build_doc(new_doc, for_publish: true)
unless is_release_candiate
current_doc = "#{tmp}/current"
build_doc(current_doc, release: "current", for_publish: true)
end
else
devel_doc = "#{tmp}/devel"
build_doc(devel_doc, release: "devel", for_publish: true)
end
add = lambda do |source, destination|
rm_rf(destination)
cp_r(source, destination)
sh("git", "add", "--force", destination)
end
cd("site") do
add.call(asf_yaml, ".asf.yaml")
add.call(index_html, "index.html")
if is_release
add.call(new_doc, new_version)
add.call(current_doc, "current") unless is_release_candiate
else
add.call(devel_doc, "devel")
end
sh("git", "commit", "-m", "Publish", "--allow-empty")
unless ENV["GITHUB_EVENT_NAME"] == "pull_request"
dry_run = []
dry_run << "--dry-run" unless ENV["GITHUB_REF_NAME"] == "main"
sh("git", "push", *dry_run, "origin", "asf-site:asf-site")
end
end
end
end
end
def load_env
env_file = "dev/release/.env"
unless File.exist?(env_file)
raise "must create #{env_file} from #{env_file}.example"
end
File.readlines(env_file, chomp: true).each do |line|
line.strip!
next if line.empty?
next if line.start_with?("#")
name, value = line.split("=", 2)
next if value.nil?
name.strip!
value.strip!
ENV[name] ||= value
end
end
def env_value(name, default=nil)
value = ENV[name]
if value.nil? and default.nil?
raise "must set environment variable: #{name}"
end
value || default
end
def github_repository
env_value("GITHUB_REPOSITORY", "apache/arrow-flight-sql-postgresql")
end
def gpg_key_id
env_value("GPG_KEY_ID")
end
def arrow_source
env_value("ARROW_SOURCE")
end
def detect_latest_rc(version)
rc_tags = `git tag`.each_line(chomp: true).select do |tag|
tag.start_with?("#{version}-rc")
end
rcs = rc_tags.collect do |rc_tag|
Integer(rc_tag.delete_prefix("#{version}-rc"), 10)
end
rcs.max
end
def package_directories
Dir.glob("package/postgresql-*")
end
def debian_changelog_latest_version(changelog_path)
(File.readlines(changelog_path)[0] || "")[/\(([\d.]+)-\d+\)/, 1]
end
def validate_rc(version)
package_directories.each do |dir|
latest_version = debian_changelog_latest_version("#{dir}/debian/changelog")
if latest_version != version
raise "'rake release:rc:prepare && git push' is needed"
end
end
release_notes = File.read("doc/source/release-notes.md").split(/^## /)
latest_release_note = release_notes[1]
latest_release_note_version = latest_release_note.lines[0].strip
if latest_release_note_version != version
raise "add a release note to doc/source/release-notes.md"
end
end
def ensure_package_job_finished(rc_tag)
run_id = nil
while run_id.nil?
runs = IO.pipe do |read, write|
sh("gh", "run", "list",
"--json", "databaseId,headBranch",
"--repo", github_repository,
"--workflow", "package.yaml",
out: write)
write.close
read.read
end
run = JSON.parse(runs).find {|rc| rc["headBranch"] == rc_tag}
run_id = run&.fetch("databaseId")
end
sh("gh", "run", "watch",
"--repo", github_repository,
"--exit-status",
run_id.to_s)
end
namespace :release do
namespace :rc do
desc "Prepare a new RC"
task :prepare do
prepared = false
package_directories.each do |dir|
cd(dir) do
debian_changelog = "debian/changelog"
latest_version = debian_changelog_latest_version(debian_changelog)
next if latest_version == version
ruby("-S", "rake", "version:update")
sh("git", "add", debian_changelog)
prepared = true
end
end
sh("git", "commit", "-m", "Prepare #{version} RC #{new_rc}")
end
desc "Tag a new RC"
task :tag do
validate_rc(version)
new_rc = (detect_latest_rc(version) || 0) + 1
rc_tag = "#{version}-rc#{new_rc}"
sh("git", "tag",
"-a", rc_tag,
"-m", "#{project_label} #{version} RC #{new_rc}")
if env_value("TAG_PUSH", "no") == "yes"
sh("git", "push", "upstream", rc_tag)
else
puts("Push #{rc_tag}:")
puts(" git push upstream #{rc_tag}")
end
end
desc "Sign the latest RC"
task :sign do
load_env
rc = detect_latest_rc(version)
if rc.nil?
raise "'rake release:rc:tag && git push ...' is needed"
end
rc_tag = "#{version}-rc#{rc}"
ensure_package_job_finished(rc_tag)
Dir.mktmpdir do |tmp|
sh("gh", "release", "download",
"--dir", tmp,
"--pattern", archive_name,
"--repo", github_repository,
rc_tag)
tmp_archive_name = "#{tmp}/#{archive_name}"
tmp_sign_name = "#{tmp_archive_name}.asc"
sh("gpg",
"--armor",
"--detach-sign",
"--local-user", gpg_key_id,
"--output", tmp_sign_name,
"#{tmp_archive_name}")
tmp_checksum_name = "#{tmp_archive_name}.sha512"
File.open(tmp_checksum_name, "w") do |output|
checksum = Digest::SHA512.file(tmp_archive_name)
output.puts("#{checksum} #{archive_name}")
end
sh("gh", "release", "upload",
"--clobber",
"--repo", github_repository,
rc_tag,
tmp_sign_name,
tmp_checksum_name)
end
end
desc "Upload Linux packages"
task :linux do
load_env
rc = detect_latest_rc(version)
if rc.nil?
raise "'rake release:rc:tag && git push ...' is needed"
end
rc_tag = "#{version}-rc#{rc}"
Dir.mktmpdir do |tmp|
sh("gh", "release", "download",
"--dir", tmp,
"--pattern", "debian-*.tar.gz",
"--pattern", "ubuntu-*.tar.gz",
"--repo", github_repository,
rc_tag)
Dir.glob("#{tmp}/*.tar.gz") do |tar_gz|
sh("tar", "xf", tar_gz,
"--directory", tmp,
"--one-top-level")
end
env = {
"ARROW_ARTIFACTS_DIR" => tmp,
"DEB_PACKAGE_NAME" => "apache-arrow-flight-sql-postgresql",
"UPLOAD_DEFAULT" => "0",
"UPLOAD_DEBIAN" => "1",
"UPLOAD_UBUNTU" => "1",
}
sh(env,
"#{arrow_source}/dev/release/05-binary-upload.sh",
version,
rc.to_s)
end
end
desc "Generate a release vote e-mail"
task :vote do
load_env
rc = detect_latest_rc(version)
if rc.nil?
raise "'rake release:rc:tag && git push ...' is needed"
end
rc_tag = "#{version}-rc#{rc}"
commit = IO.pipe do |read, write|
sh("git", "rev-list", "-n", "1", rc_tag, write: write)
write.close
read.read.strip
end
puts(<<-MAIL)
local -r commit=$(git rev-list -n 1 "${tag}")
cat <<MAIL
To: dev@arrow.apache.org
Subject: [VOTE] Release Apache Arrow Flight SQL adapter for PostgreSQL ${version} - RC#{rc}
Hi,
I would like to propose the following release candidate (RC#{rc}) of
Apache Arrow Flight SQL adapter for PostgreSQL version #{version}.
This release candidate is based on commit: #{commit} [1]
The source release rc#{rc} and changelog is hosted at [2].
The binary artifacts are hosted at [3][4].
Please download, verify checksums and signatures, build and run,
and vote on the release. See [5] for how to validate a release
candidate.
The vote will be open for at least 24 hours because Apache Arrow
Flight SQL adapter for PostgreSQL doesn't reach 1.0.0 yet.
[ ] +1 Release this as Apache Arrow Flight SQL adapter for PostgreSQL #{version}
[ ] +0
[ ] -1 Do not release this as Apache Arrow Flight SQL adapter for PostgreSQL #{version}
because...
[1]: https://github.com/apache/arrow-flight-sql-postgresql/commit/#{commit}
[2]: https://github.com/apache/arrow-flight-sql-postgresql/releases/tag/#{rc_tag}
[3]: https://apache.jfrog.io/artifactory/arrow/debian-rc/
[4]: https://apache.jfrog.io/artifactory/arrow/ubuntu-rc/
[5]: https://arrow.apache.org/flight-sql-postgresql/devel/release.html#how-to-verify-release-candidates
MAIL
end
namespace :publish do
desc "Publish to https://dist.apache.org/"
task :apache do
load_env
rc = detect_latest_rc(version)
rc_tag = "#{version}-rc#{rc}"
Dir.mktmpdir do |tmp|
sh("svn", "co",
"--depth=empty",
"https://dist.apache.org/repos/dist/release/arrow",
tmp)
release_dir = "#{tmp}/apache-arrow-flight-sql-postgresql-#{verison}"
mkdir_p(release_dir)
sh("gh", "release", "download",
"--dir", release_dir,
"--pattern", "#{archive_name}*",
"--repo", github_repository,
rc_tag)
sh("svn", "add", release_dir)
sh("svn", "ci", "-m", "#{project_label} #{version}", release_dir)
end
end
desc "Register a new release to https://reporter.apache.org/"
task :reporter do
sh("open", "https://reporter.apache.org/addrelease.html?arrow")
end
desc "Publish Linux packages"
task :linux do
rc = detect_latest_rc(version)
env = {
"UPLOAD_DEFAULT" => "0",
"UPLOAD_DEBIAN" => "1",
"UPLOAD_UBUNTU" => "1",
}
sh(env,
"#{arrow_source}/dev/release/post-02-binary.sh",
version,
rc.to_s)
end
desc "Tag #{version}"
task :tag do
load_env
rc = detect_latest_rc(version)
rc_tag = "#{version}-rc#{rc}"
sh("git", "tag",
"-a", version,
"-m", "#{project_label} #{version}",
"#{rc_tag}^{}")
if env_value("TAG_PUSH", "no") == "yes"
sh("git", "push", "upstream", version)
else
puts("Push #{version}:")
puts(" git push upstream #{version}")
end
end
end
desc "Publish the latest RC as a new release"
task :publish => [
"release:rc:publish:apache",
"release:rc:publish:reporter",
"release:rc:publish:linux",
"release:rc:publish:tag",
]
end
end