blob: 1e9a7af1d50c901100055247f6a4e36c8aeb051b [file] [log] [blame]
# 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.
import distutils.dir_util
import json
import os
import re
import shutil
import tarfile
from os import fdopen, remove
from shutil import move, copymode
from tempfile import mkstemp
import git
def build_release():
tools_dir = os.path.dirname(os.path.realpath(__file__))
# load configs
config_file = os.path.join(tools_dir, "release-configs.json")
with open(config_file) as configs:
data = json.load(configs)
release_meta = data["release"]
version = release_meta["version"]
release_package_name = "apache-yunikorn-{0}-incubating-src".format(version)
repo_list = data["repositories"]
print("release meta info:")
print(" - main version: %s" % version)
print(" - release package name: %s" % release_package_name)
staging_dir = os.path.join(os.path.dirname(tools_dir), "staging")
release_base = os.path.join(staging_dir, release_package_name)
release_top_path = os.path.join(os.path.dirname(tools_dir), "release-top-level-artifacts")
helm_chart_path = os.path.join(os.path.dirname(tools_dir), "helm-charts")
# setup artifacts in the release base dir
setup_base_dir(release_top_path, helm_chart_path, release_base, version)
# download source code from github repo
sha = dict()
for repo_meta in repo_list:
sha[repo_meta["name"]] = download_sourcecode(release_base, repo_meta)
update_make_version(repo_meta["name"], os.path.join(release_base, repo_meta["alias"]), version)
# update the sha for all repos in the build scripts
# must be run after all repos have been checked out
update_sha(release_base, repo_list, sha)
# generate tarball
tarball_name = release_package_name + ".tar.gz"
tarball_path = os.path.join(staging_dir, tarball_name)
print("creating tarball %s" % tarball_path)
with tarfile.open(tarball_path, "w:gz") as tar:
tar.add(os.path.join(release_base, "LICENSE"), arcname=release_package_name + "/LICENSE")
tar.add(release_base, arcname=release_package_name, filter=exclude_files)
def exclude_files(tarinfo):
file_name = os.path.basename(tarinfo.name)
exclude = [".git", ".github", ".gitignore", ".travis.yml", ".asf.yaml", ".golangci.yml", ".helmignore", "LICENSE",
"landmark"]
if file_name in exclude:
print("exclude file from tarball %s" % tarinfo.name)
return None
return tarinfo
def setup_base_dir(release_top_path, helm_path, base_path, version):
print("setting up base dir for release artifacts, path: %s" % base_path)
if os.path.exists(base_path):
raise Exception("staging dir %s already exist, please remove it and retry" % base_path)
# setup base dir
os.makedirs(base_path)
# copy top level artifacts
for file in os.listdir(release_top_path):
org = os.path.join(release_top_path, file)
dest = os.path.join(base_path, file)
print("copying files: %s ===> %s" % (org, dest))
shutil.copy2(org, dest)
# set the base Makefile version info
replace(os.path.join(base_path, "Makefile"), 'latest', version)
# copy the helm charts
copy_helm_charts(helm_path, base_path, version)
# copy the helm charts into the base path and replace the version to the one defined in config
def copy_helm_charts(helm_path, base_path, version):
print("helm patch: %s, base path: %s", helm_path, base_path)
release_helm_path = os.path.join(base_path, "helm-charts")
distutils.dir_util.copy_tree(helm_path, release_helm_path)
# rename the version in the helm charts to the actual version
yunikorn_chart_path = os.path.join(release_helm_path, "yunikorn")
replace(os.path.join(yunikorn_chart_path, "values.yaml"), 'tag: scheduler-.*', 'tag: scheduler-' + version)
replace(os.path.join(yunikorn_chart_path, "values.yaml"), 'tag: admission-.*', 'tag: admission-' + version)
replace(os.path.join(yunikorn_chart_path, "values.yaml"), 'tag: web-.*', 'tag: web-' + version)
replace(os.path.join(yunikorn_chart_path, "Chart.yaml"), 'version: .*', 'version: ' + version)
replace(os.path.join(yunikorn_chart_path, "Chart.yaml"), 'appVersion: .*', 'appVersion: \"' + version + '\"')
# replaces the string that match to pattern to subst from the file_path
def replace(file_path, pattern, subst):
# Create temp file
fh, abs_path = mkstemp()
with fdopen(fh, 'w') as new_file:
with open(file_path) as old_file:
for line in old_file:
new_line = re.sub(pattern, subst, line)
new_file.write(new_line)
# Copy the file permissions from the old file to the new file
copymode(file_path, abs_path)
# Remove original file
remove(file_path)
# Move new file
move(abs_path, file_path)
def download_sourcecode(base_path, repo_meta):
print("downloading source code")
print("repository info:")
print(" - repository: %s " % repo_meta["repository"])
print(" - description: %s " % repo_meta["description"])
print(" - tag: %s " % repo_meta["tag"])
repo = git.Repo.clone_from(
url=repo_meta["repository"],
to_path=os.path.join(base_path, repo_meta["alias"]))
repo.git.checkout(repo_meta["tag"])
tag = repo.tag("refs/tags/" + repo_meta["tag"])
sha = tag.commit.hexsha
print(" - tag sha: %s " % sha)
# avoid pulling dependencies from github,
# add replace to go mod files to make sure it builds locally
update_dep_ref(repo_meta["name"], os.path.join(base_path, repo_meta["alias"]))
return sha
# K8shim depends on yunikorn-core and scheduler-interface
def update_dep_ref_k8shim(local_repo_path):
print("updating dependency for k8shim")
mod_file = os.path.join(local_repo_path, "go.mod")
with open(mod_file, "a") as file_object:
file_object.write("\n")
file_object.write("replace github.com/apache/incubator-yunikorn-core => ../core \n")
file_object.write(
"replace github.com/apache/incubator-yunikorn-scheduler-interface => ../scheduler-interface \n")
# core depends on scheduler-interface
def update_dep_ref_core(local_repo_path):
print("updating dependency for core")
mod_file = os.path.join(local_repo_path, "go.mod")
with open(mod_file, "a") as file_object:
file_object.write("\n")
file_object.write(
"replace github.com/apache/incubator-yunikorn-scheduler-interface => ../scheduler-interface \n")
# update go mod in the repos
def update_dep_ref(repo_name, local_repo_path):
switcher = {
"yunikorn-k8shim": update_dep_ref_k8shim,
"yunikorn-core": update_dep_ref_core,
}
if switcher.get(repo_name) is not None:
switcher.get(repo_name)(local_repo_path)
# replace the default version to release version in the Makefile(s)
def update_make_version(repo_name, local_repo_path, version):
switcher = {
"yunikorn-k8shim": "update",
"yunikorn-web": "update",
}
if switcher.get(repo_name) is not None:
replace(os.path.join(local_repo_path, "Makefile"), 'latest', version)
# k8shim uses its own, yunikorn-core and scheduler-interface revisions
def update_sha_shim(repo_name, local_repo_path, sha):
print("updating sha for k8shim")
make_file = os.path.join(local_repo_path, "Makefile")
replace(make_file, 'coreSHA=.*\\)', 'coreSHA=' + sha["yunikorn-core"])
replace(make_file, 'siSHA=.*\\)', 'siSHA=' + sha["yunikorn-scheduler-interface"])
replace(make_file, 'shimSHA=.*\\)', 'shimSHA=' + sha[repo_name])
# web only uses its own revision
def update_sha_web(repo_name, local_repo_path, sha):
print("updating sha for web")
replace(os.path.join(local_repo_path, "Makefile"), "SHA=.*\\)", 'SHA=' + sha[repo_name])
# update git revision in the makefiles
def update_sha(release_base, repo_list, sha):
for repo_meta in repo_list:
repo_name = repo_meta["name"]
switcher = {
"yunikorn-k8shim": update_sha_shim,
"yunikorn-web": update_sha_web,
}
if switcher.get(repo_name) is not None:
switcher.get(repo_name)(repo_name, os.path.join(release_base, repo_meta["alias"]), sha)
def main():
build_release()
if __name__ == "__main__":
main()