def prompt_for_message(html_url, summaries): """ Prompts the user for a release message in an editor, showing them the commits since last release, and returns what the user specified Args: html_url: The url to see the difference between the current commit and the commit for the previous release. summaries: The commit summaries to display to the user """ default_message = create_default_message(html_url) summaries_text = "\n".join(("# " + line for line in summaries)) full_message = MESSAGE_PROMPT_TEMPLATE.format( default_message=default_message, commit_messages=summaries_text) temp_fd, temp_path = tempfile.mkstemp() try: with open(temp_path, "w") as fout: fout.write(full_message) editor = os.environ.get("EDITOR", "vim") run([editor, temp_path]) with open(temp_path, "r") as fin: message = "\n".join(line for line in fin if not line.startswith("#")) message = message.strip() if not message: raise ReleaseException("No valid message was provided") return message finally: if os.path.exists(temp_path): os.remove(temp_path)
def prompt_for_message(html_url, summaries): """ Prompts the user for a release message in an editor, showing them the commits since last release, and returns what the user specified Args: html_url: The url to see the difference between the current commit and the commit for the previous release. summaries: The commit summaries to display to the user """ default_message = create_default_message(html_url) summaries_text = "\n".join(("# " + line for line in summaries)) full_message = MESSAGE_PROMPT_TEMPLATE.format( default_message=default_message, commit_messages=summaries_text ) temp_fd, temp_path = tempfile.mkstemp() try: with open(temp_path, "w") as fout: fout.write(full_message) editor = os.environ.get("EDITOR", "vim") run([editor, temp_path]) with open(temp_path, "r") as fin: message = "\n".join(line for line in fin if not line.startswith("#")) message = message.strip() if not message: raise ReleaseException("No valid message was provided") return message finally: if os.path.exists(temp_path): os.remove(temp_path)
def prompt_for_message(summaries): """ Prompts the user for a release message in an editor, showing them the commits since last release, and returns what the user specified Args: summaries: The commit summaries to display to the user """ summaries_text = "\n".join(("# " + line for line in summaries)) temp_fd, temp_path = tempfile.mkstemp() try: with open(temp_path, "w") as fout: fout.write(MESSAGE_TEMPLATE.format(commit_messages=summaries_text)) editor = os.environ.get("EDITOR", "vim") run([editor, temp_path]) with open(temp_path, "r") as fin: message = "\n".join(line for line in fin if not line.startswith("#")) message = message.strip() if not message: raise ReleaseException("No valid message was provided") return message finally: if os.path.exists(temp_path): os.remove(temp_path)
def docker_login(): username = os.environ.get("DOCKERHUB_USERNAME") token = os.environ.get("DOCKERHUB_TOKEN") if username and token: run(["docker", "login", "--username", username, "--password-stdin"], input=token) else: logging.error( "Both DOCKERHUB_USERNAME and DOCKERHUB_TOKEN must be set to login to dockerhub" )
def install_homebrew(homebrew_dir): logging.info("Installing homebrew to {}".format(homebrew_dir)) if not os.path.exists(homebrew_dir): os.makedirs(homebrew_dir) logging.info("Downloading homebrew...") response = requests.get("https://github.com/Homebrew/brew/tarball/master", stream=True) response.raise_for_status() with tempfile.NamedTemporaryFile() as fout: for chunk in response.iter_content(1024 * 1024): fout.write(chunk) fout.flush() logging.info("Extracting homebrew...") run(["tar", "xzf", fout.name, "--strip", "1", "-C", homebrew_dir]) logging.info("Extracted homebrew")
def install_homebrew(homebrew_dir): logging.info("Installing homebrew to {}".format(homebrew_dir)) if not os.path.exists(homebrew_dir): os.makedirs(homebrew_dir) logging.info("Downloading homebrew...") response = requests.get( "https://github.com/Homebrew/brew/tarball/master", stream=True ) response.raise_for_status() with tempfile.NamedTemporaryFile() as fout: for chunk in response.iter_content(1024 * 1024): fout.write(chunk) fout.flush() logging.info("Extracting homebrew...") run(["tar", "xzf", fout.name, "--strip", "1", "-C", homebrew_dir]) logging.info("Extracted homebrew")
def validate_environment(args): """ Make sure we can build """ validate_repo_upstream(args) if args.build_deb: ret = docker( args.docker_linux_host, ["info", "-f", "{{.OSType}}"], check=False, capture_output=True, ) host = args.docker_linux_host or "localhost" if ret.returncode != 0: raise ReleaseException( "docker info on linux host {} failed. debs cannot be built", host ) host_os = ret.stdout.decode("utf-8").strip() if host_os != "linux": raise ReleaseException( "docker info on host {} returned type '{}' not 'linux'. debs cannot be built", host, host_os, ) if args.build_chocolatey: ret = docker( args.docker_windows_host, ["info", "-f", "{{.OSType}}"], check=False, capture_output=True, ) host = args.docker_windows_host or "localhost" if ret.returncode != 0: raise ReleaseException( "docker info on windows host {} failed. chocolatey nupkgs cannot be built", host, ) host_os = ret.stdout.decode("utf-8").strip() if host_os != "windows": raise ReleaseException( "docker info on host {} returned type '{}' not 'windows'. chocolatey nupkgs cannot be built", host, host_os, ) if args.build_homebrew: if args.homebrew_dir: if not os.path.exists(args.homebrew_dir): raise ReleaseException( "Specified homebrew path, {}, does not exist", args.homebrew_dir ) brew_path = os.path.join(args.homebrew_dir, "bin", "brew") try: ret = run([brew_path, "--version"]) except Exception: raise ReleaseException( "{} --version failed. bottles cannot be created", brew_path )
def validate_environment(args): """ Make sure we can build """ validate_repo_upstream(args) if args.build_deb: ret = docker( args.docker_linux_host, ["info", "-f", "{{.OSType}}"], check=False, capture_output=True, ) host = args.docker_linux_host or "localhost" if ret.returncode != 0: raise ReleaseException( "docker info on linux host {} failed. debs cannot be built", host) host_os = ret.stdout.decode("utf-8").strip() if host_os != "linux": raise ReleaseException( "docker info on host {} returned type '{}' not 'linux'. debs cannot be built", host, host_os, ) if args.build_chocolatey: ret = docker( args.docker_windows_host, ["info", "-f", "{{.OSType}}"], check=False, capture_output=True, ) host = args.docker_windows_host or "localhost" if ret.returncode != 0: raise ReleaseException( "docker info on windows host {} failed. chocolatey nupkgs cannot be built", host, ) host_os = ret.stdout.decode("utf-8").strip() if host_os != "windows": raise ReleaseException( "docker info on host {} returned type '{}' not 'windows'. chocolatey nupkgs cannot be built", host, host_os, ) if args.build_homebrew: if args.homebrew_dir: if not os.path.exists(args.homebrew_dir): raise ReleaseException( "Specified homebrew path, {}, does not exist", args.homebrew_dir) brew_path = os.path.join(args.homebrew_dir, "bin", "brew") try: ret = run([brew_path, "--version"]) except Exception: raise ReleaseException( "{} --version failed. bottles cannot be created", brew_path)
def brew(homebrew_dir, command, *run_args, **run_kwargs): """ Run brew that is installed in the specified prefix. Args: homebrew_dir: The path containing bin/brew. e.g. /usr/local command: The list of args to pass to the brew command run_args: Extra args to send to platforms.common.run run_kwargs: Extra kwargs to send to platforms.common.run Returns: Result from subprocess.run """ brew_path = os.path.join(homebrew_dir, "bin", "brew") return run([brew_path] + command, *run_args, **run_kwargs)
def prompt_for_message(summaries): """ Prompts the user for a release message in an editor, showing them the commits since last release, and returns what the user specified Args: summaries: The commit summaries to display to the user """ summaries_text = "\n".join(("# " + line for line in summaries)) temp_fd, temp_path = tempfile.mkstemp() try: with open(temp_path, "w") as fout: fout.write(MESSAGE_PROMPT_TEMPLATE.format(commit_messages=summaries_text)) editor = os.environ.get("EDITOR", "vim") run([editor, temp_path]) with open(temp_path, "r") as fin: message = "\n".join(line for line in fin if not line.startswith("#")) message = message.strip() if not message: raise ReleaseException("No valid message was provided") return message finally: if os.path.exists(temp_path): os.remove(temp_path)
def push_tap(git_repository, tap_path, version, github_token): """ Grab any working directory changes for the tap, clone a new tap repository, and push those changes upstream. The original tap path is in a clean state after this push. The clone is done with ssh, so ssh keys must be available Args: git_repository: The repo on github that needs to be cloned/pushed to tap_path: The directory that the tap (with changes) exists in version: The version to use in commit messages """ logging.info("Gathering git diff from {}".format(tap_path)) git_diff = run(["git", "diff"], tap_path, True).stdout user = get_current_user(github_token) git_url = "https://{}:{}@github.com/{}.git".format(user["login"], github_token, git_repository) with tempfile.TemporaryDirectory() as temp_dir: logging.info("Cloning {} into {}".format(git_url, temp_dir)) run(["git", "clone", git_url, temp_dir]) logging.info("Cloned into {}. Applying patch".format(temp_dir)) run(["git", "apply", "-"], temp_dir, input=git_diff) logging.info("Committing...") with tempfile.NamedTemporaryFile() as fout: commit_message = ( "Bump buck to version {}\n\nThis commit was generated by " "release automation\n").format(version) fout.write(commit_message.encode("utf-8")) fout.flush() run(["git", "commit", "-F", fout.name, "buck.rb"], temp_dir) logging.info("Pushing commit upstream") run(["git", "push", "origin"], temp_dir) logging.info("Pushed commit upstream!") logging.info( "Resetting state of {}, and updating it after push".format(tap_path)) run(["git", "checkout", "buck.rb"], tap_path) run(["git", "checkout", "master"], tap_path) run(["git", "pull"], tap_path) logging.info( "Reset state of {}, and updating it after push".format(tap_path))
def push_tap(git_repository, tap_path, version): """ Grab any working directory changes for the tap, clone a new tap repository, and push those changes upstream. The original tap path is in a clean state after this push. The clone is done with ssh, so ssh keys must be available Args: git_repository: The repo on github that needs to be cloned/pushed to tap_path: The directory that the tap (with changes) exists in version: The version to use in commit messages """ logging.info("Gathering git diff from {}".format(tap_path)) git_diff = run(["git", "diff"], tap_path, True).stdout git_url = "[email protected]:{}.git".format(git_repository) with tempfile.TemporaryDirectory() as temp_dir: logging.info("Cloning {} into {}".format(git_url, temp_dir)) run(["git", "clone", git_url, temp_dir]) logging.info("Cloned into {}. Applying patch".format(temp_dir)) run(["git", "apply", "-"], temp_dir, input=git_diff) logging.info("Committing...") with tempfile.NamedTemporaryFile() as fout: commit_message = ( "Bump buck to version {}\n\nThis commit was generated by " "release automation\n" ).format(version) fout.write(commit_message.encode("utf-8")) fout.flush() run(["git", "commit", "-F", fout.name, "buck.rb"], temp_dir) logging.info("Pushing commit upstream") run(["git", "push", "origin"], temp_dir) logging.info("Pushed commit upstream!") logging.info("Resetting state of {}, and updating it after push".format(tap_path)) run(["git", "checkout", "buck.rb"], tap_path) run(["git", "checkout", "master"], tap_path) run(["git", "pull"], tap_path) logging.info("Reset state of {}, and updating it after push".format(tap_path))