utils/build-dists.py (101 lines of code) (raw):

# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. 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. """A command line tool for building and verifying releases.""" import contextlib import os import re import shlex import shutil import sys import tempfile base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) tmp_dir = None @contextlib.contextmanager def set_tmp_dir(): global tmp_dir tmp_dir = tempfile.mkdtemp() yield tmp_dir shutil.rmtree(tmp_dir) tmp_dir = None def run(*argv, expect_exit_code=0): global tmp_dir if tmp_dir is None: os.chdir(base_dir) else: os.chdir(tmp_dir) cmd = " ".join(shlex.quote(x) for x in argv) print("$ " + cmd) exit_code = os.system(cmd) if exit_code != expect_exit_code: print( "Command exited incorrectly: should have been %d was %d" % (expect_exit_code, exit_code) ) exit(exit_code or 1) def test_dist(dist): with set_tmp_dir() as tmp_dir: # Build the venv and install the dist run("python", "-m", "venv", os.path.join(tmp_dir, "venv")) venv_python = os.path.join(tmp_dir, "venv/bin/python") run(venv_python, "-m", "pip", "install", "-U", "pip", "mypy") run(venv_python, "-m", "pip", "install", dist) # Test the namespace and top-level clients run(venv_python, "-c", "import elastic_enterprise_search") for client in ("EnterpriseSearch", "AppSearch", "WorkplaceSearch"): run(venv_python, "-c", f"from elastic_enterprise_search import {client}") # Uninstall and ensure that clients aren't available run(venv_python, "-m", "pip", "uninstall", "--yes", "elastic-enterprise-search") run(venv_python, "-c", "import elastic_enterprise_search", expect_exit_code=256) for client in ("EnterpriseSearch", "AppSearch", "WorkplaceSearch"): run( venv_python, "-c", f"from elastic_enterprise_search import {client}", expect_exit_code=256, ) def main(): run("rm", "-rf", "build/", "dist/*", "*.egg-info", ".eggs") # Grab the major version to be used as a suffix. version_path = os.path.join(base_dir, "elastic_enterprise_search/_version.py") with open(version_path) as f: version = re.search( r"^__version__\s+=\s+[\"\']([^\"\']+)[\"\']", f.read(), re.M ).group(1) # If we're handed a version from the build manager we # should check that the version is correct or write # a new one. if len(sys.argv) >= 2: # 'build_version' is what the release manager wants, # 'expect_version' is what we're expecting to compare # the package version to before building the dists. build_version = expect_version = sys.argv[1] # '-SNAPSHOT' means we're making a pre-release. if "-SNAPSHOT" in build_version: # If there's no +dev already (as is the case on dev # branches like 7.x, master) then we need to add one. if not version.endswith("+dev"): version = version + "+dev" expect_version = expect_version.replace("-SNAPSHOT", "") if expect_version.endswith(".x"): expect_version = expect_version[:-2] # For snapshots we ensure that the version in the package # at least *starts* with the version. This is to support # build_version='7.x-SNAPSHOT'. if not version.startswith(expect_version): print( "Version of package (%s) didn't match the " "expected release version (%s)" % (version, build_version) ) exit(1) # A release that will be tagged, we want # there to be no '+dev', etc. elif expect_version != version: print( "Version of package (%s) didn't match the " "expected release version (%s)" % (version, build_version) ) exit(1) # Ensure that the version within 'elasticsearch/_version.py' is correct. with open(version_path) as f: version_data = f.read() version_data = re.sub( r"__version__ = \"[^\"]+\"", f'__version__ = "{version}"', version_data, ) with open(version_path, "w") as f: f.truncate() f.write(version_data) # Build the sdist/wheels run("python", "-m", "build") # Test everything that got created dists = os.listdir(os.path.join(base_dir, "dist")) assert len(dists) == 2 for dist in dists: test_dist(os.path.join(base_dir, "dist", dist)) run("git", "checkout", "--", "elastic_enterprise_search/") # After this run 'python -m twine upload dist/*' print( "\n\n" "===============================\n\n" " * Releases are ready! *\n\n" "$ python -m twine upload dist/*\n\n" "===============================" ) if __name__ == "__main__": main()