def sync_conan_repo(conan_details: ConanReleaseDetails, project_details: ProjectDetails, new_version: Version) -> None: print('Updating conan repo and creating branch') with use_directory(conan_details.conan_repo_dir): print(os.getcwd()) repo = Repo('.') repo.git.checkout('master') repo.remote('upstream').pull('master') repo.remote('origin').push('master') new_branch = PrepareConanRelease.get_new_branch_name( project_details, new_version) print(repo.heads) if new_branch in repo.heads: def delete_branch() -> None: print(f"Deleting previously-created branch {new_branch}") repo.delete_head( new_branch) # only works if not checked out optional_action( f'Branch {new_branch} already exists in conan repo: Do you want to delete it?', delete_branch) current = repo.create_head(new_branch) current.checkout()
def sync_vcpkg_repo(vcpkg_details: VcpkgReleaseDetails, project_details: ProjectDetails, new_version: Version) -> None: print('Updating vcpkg repo and creating branch') with use_directory(vcpkg_details.vcpkg_repo_dir): print(os.getcwd()) repo = Repo('.') repo.git.checkout('master') repo.remote('upstream').pull('master') try: repo.remote('origin').push('master') except GitCommandError: # If we are only preparing a release, not deploying, a failure # to push here (e.g. if being from GitHub Actions, to test release # preparation) is harmless, so just continue. print( f"INFO: No permission to push to remote repo in {vcpkg_details.vcpkg_repo_dir}" ) new_branch = PrepareVcpkgRelease.get_new_branch_name( project_details, new_version) print(repo.heads) if new_branch in repo.heads: def delete_branch() -> None: print(f"Deleting previously-created branch {new_branch}") repo.delete_head( new_branch) # only works if not checked out optional_action( f'Branch {new_branch} already exists in vcpkg repo: Do you want to delete it?', delete_branch) current = repo.create_head(new_branch) current.checkout()
def test_conan_and_create_pr(details: ReleaseDetails) -> None: with use_directory( os.path.join(ConanReleaseDetails().conan_approvaltests_dir, 'all')): # We cannot test the new Conan recipe until the new release has been # published on github new_version_without_v = details.new_version.get_version_text_without_v( ) run(['conan', 'create', '.', F'{new_version_without_v}@']) check_step( F"Commit the changes - with message 'Add approvaltests.cpp {new_version_without_v}'" ) check_step( 'Push the changes - NB on the feature branch for the release') new_branch = PrepareConanRelease.get_new_branch_name( details.new_version) run([ "open", F'https://github.com/conan-io/conan-center-index/compare/master...claremacrae:{new_branch}?expand=1' ]) description = F'** approvaltests.cpp / {new_version_without_v} **' pyperclip.copy(description) print( F"Create a pull request, including this at the start of the description (which is on your clipboard): {description}" ) check_step( "that you have created a Pull Request for conan-center-index?")
def create_single_header_file(self) -> str: self.create_simulated_single_header_file(include_cpps=True) simulated_single_header = os.path.abspath( self.details.locations.simulated_single_header_file_path) with use_directory("../build"): print(os.getcwd()) self.run_for_approval_tests(simulated_single_header, self.details.release_new_single_header) text = read_file(self.details.release_new_single_header) text = ( f'// {self.details.project_details.github_project_name} version {self.details.new_version_as_text()}\n' f'// More information at: {self.details.project_details.github_project_url}\n' '\n' '//----------------------------------------------------------------------\n' '// Welcome to Approval Tests.\n' '//\n' '// If you experience linker errors about missing symbols, it means\n' '// you have forgotten to configure your test framework for Approval Tests.\n' '//\n' '// For help with this, please see:\n' '// https://github.com/approvals/ApprovalTests.cpp/blob/master/doc/TroubleshootingMisconfiguredMain.md\n' '//----------------------------------------------------------------------\n' f'{text}') write_file(self.details.release_new_single_header, text) # HACK! A side-effect of this method is that it overwrites # the version-controlled simulated single-header, including .cpp # files. # Revert that change: self.create_simulated_single_header_file(include_cpps=False) return os.path.abspath(self.details.release_new_single_header)
def update_version_number_header(self) -> None: with use_directory(release_constants.approval_tests_dir): version_header = os.path.join("ApprovalTestsVersion.h") text = CppGeneration.get_version_number_hpp_text( self.details.new_version) write_file(version_header, text)
def create_single_header_file(self) -> str: self.create_simulated_single_header_file(include_cpps=True) simulated_single_header = os.path.abspath( self.details.locations.simulated_single_header_file_path) with use_directory("../build"): print(os.getcwd()) self.run_for_approval_tests(simulated_single_header, self.details.release_new_single_header) text = read_file(self.details.release_new_single_header) text = ( f'// {self.details.project_details.github_project_name} version {self.details.new_version_as_text()}\n' f'// More information at: {self.details.project_details.github_project_url}\n' '\n' f'{text}') write_file(self.details.release_new_single_header, text) # HACK! A side-effect of this method is that it overwrites # the version-controlled simulated single-header, including .cpp # files. # Revert that change: self.create_simulated_single_header_file(include_cpps=False) return os.path.abspath(self.details.release_new_single_header)
def update_version_number_header(self) -> None: with use_directory(self.details.locations.approval_tests_dir): version_header = os.path.join( self.details.project_details.version_header) text = CppGeneration.get_version_number_hpp_text( self.details.new_version, self.details.project_details) write_file(version_header, text)
def reset_and_clean_working_directory(project_dir: str) -> None: with use_directory(project_dir): # Delete untracked files: # - does not delete ignored files # - does not delete untracked files in new, untracked directories run(["git", "clean", "-f"]) run(["git", "reset", "--hard"])
def test_conan_build_passes(conan_details: ConanReleaseDetails, version_without_v: str) -> None: conan_directory = os.path.join(conan_details.conan_approvaltests_dir, 'all') with use_directory(conan_directory): run([ 'conan', 'create', '--build=missing', '.', F'{version_without_v}@' ])
def create_single_header_file(self) -> str: self.create_simulated_single_header_file(include_cpps=True) simulated_single_header = os.path.abspath( self.details.locations.simulated_single_header_file_path) with use_directory("../build"): print(os.getcwd()) self.run_for_approval_tests(simulated_single_header, self.details.release_new_single_header) text = read_file(self.details.release_new_single_header) year = datetime.now().year text = ( f'// {self.details.project_details.github_project_name} version {self.details.new_version_as_text()}\n' f'// More information at: {self.details.project_details.github_project_url}\n' f'//\n' f'// Copyright (c) {year} Llewellyn Falco and Clare Macrae. All rights reserved.\n' f'//\n' f'// Distributed under the Apache 2.0 License\n' f'// See https://opensource.org/licenses/Apache-2.0\n' f'\n' '//----------------------------------------------------------------------\n' '// Welcome to Approval Tests.\n' '//\n' '// If you experience linker errors about missing symbols, it means\n' '// you have forgotten to configure your test framework for Approval Tests.\n' '//\n' '// For help with this, please see:\n' '// https://github.com/approvals/ApprovalTests.cpp/blob/master/doc/TroubleshootingMisconfiguredMain.md\n' '//----------------------------------------------------------------------\n' f'{text}') write_file(self.details.release_new_single_header, text) # HACK! A side-effect of this method is that it overwrites # the version-controlled simulated single-header, including .cpp # files. # Revert that change: self.create_simulated_single_header_file(include_cpps=False) # Check for broken headers in the generated text # (but only after we have reverted any modified source code) header_files_h = SingleHeaderFile.get_all_files('.', '.h') header_files_hpp = SingleHeaderFile.get_all_files('.', '.hpp') errors = CppGeneration.validate_single_header_file_content( header_files_h, header_files_hpp, text) if errors != "": raise RuntimeError(errors) return os.path.abspath(self.details.release_new_single_header)
def sync_conan_repo(new_version: Version) -> None: print('Updating conan repo and creating branch') with use_directory(ConanReleaseDetails().conan_repo_dir): print(os.getcwd()) repo = Repo('.') repo.git.checkout('master') repo.remote('upstream').pull('master') repo.remote('origin').push('master') # TODO If we had previously created the branch for this release version, and then # changes were pushed to conan master, we will get an error about the # branch already existing, but pointing to a different change new_branch = PrepareConanRelease.get_new_branch_name(new_version) current = repo.create_head(new_branch) current.checkout()
def sync_conan_repo(conan_details: ConanReleaseDetails, project_details: ProjectDetails, new_version: Version) -> None: print('Updating conan repo and creating branch') with use_directory(conan_details.conan_repo_dir): print(os.getcwd()) repo = Repo('.') repo.git.checkout('master') repo.remote('upstream').pull('master') repo.remote('origin').push('master') new_branch = PrepareConanRelease.get_new_branch_name( project_details, new_version) current = repo.create_head(new_branch) current.checkout()
def create_single_header_file(self) -> str: self.create_simulated_single_header_file() simulated_single_header = os.path.abspath( release_constants.simulated_single_header_file_path) with use_directory("../build"): print(os.getcwd()) self.run_for_approval_tests(simulated_single_header, self.details.release_new_single_header) text = read_file(self.details.release_new_single_header) text = ( f'// Approval Tests version {self.details.new_version_as_text()}\n' '// More information at: https://github.com/approvals/ApprovalTests.cpp\n' '\n' f'{text}') write_file(self.details.release_new_single_header, text) return os.path.abspath(self.details.release_new_single_header)
def commit_main_project(self) -> None: with use_directory(release_constants.main_project_dir): run([ "git", "commit", "-m", F"'{self.details.new_version_as_text()} release'" ])
def update_readme_and_docs(details: ReleaseDetails) -> None: with use_directory(".."): replace_text_in_file("mdsource/README.source.md", details.old_version_as_text(), details.new_version_as_text())
def regenerate_markdown() -> None: with use_directory(".."): run(["./run_markdown_templates.sh"])
def do_things_in_starter_project_and_main(self, function: Callable) -> None: with use_directory(release_constants.starter_project_dir): function() with use_directory(release_constants.main_project_dir): function()
def check_starter_project_builds(self) -> None: with use_directory( F"{release_constants.starter_project_dir}/cmake-build-debug"): run(["cmake", "--build", "."])
def push_main_project(self) -> None: with use_directory(self.details.locations.main_project_dir): run(["git", "push", "origin", "master"])
def add_everything(directory: str) -> None: with use_directory(directory): run(["git", "add", "."])
def update_pom(details: ReleaseDetails) -> None: with use_directory(release_constants.starter_project_dir): old = details.old_version.get_version_text_without_v() new = details.new_version.get_version_text_without_v() replace_text_in_file("pom.xml", old, new)
def check_starter_project_builds(details: ReleaseDetails) -> None: build_dir = F"{details.locations.starter_project_dir}/cmake-build-validate-release" ensure_directory_exists(build_dir) with use_directory(build_dir): run(["cmake", ".."]) run(["cmake", "--build", "."])
def commit_starter_project(self) -> None: with use_directory(release_constants.starter_project_dir): run([ "git", "commit", "-m", F"'Update to Approvals {self.details.new_version_as_text()}'" ])
def do_things_in_starter_project_and_main(self, function: Callable) -> None: with use_directory(self.details.locations.starter_project_dir): function() with use_directory(self.details.locations.main_project_dir): function()
def check_starter_project_builds(self) -> None: with use_directory(F"{self.details.locations.starter_project_dir}/cmake-build-debug"): run(["cmake", "--build", "."])
def test_with_push_directory(self) -> None: cwd = os.getcwd() with use_directory('..'): self.assertNotEqual(cwd, os.getcwd()) self.assertEqual(cwd, os.getcwd())
def push_starter_project(details: ReleaseDetails) -> None: with use_directory(details.locations.starter_project_dir): run(["git", "push", "origin", "master"])
def push_main_project(self) -> None: with use_directory(release_constants.main_project_dir): run(["git", "push", "origin", "master"])
def commit_everything(directory: str, message: str) -> None: with use_directory(directory): run(["git", "commit", "-m", F"'{message}'"])