def test_latest_version(git_repo): git('tag', '0.0.2') git('tag', '0.0.3') repository = GitRepository() expected_versions = [Version('0.0.1'), Version('0.0.2'), Version('0.0.3')] assert expected_versions == repository.versions assert Version('0.0.3') == repository.latest_version
def download(self): from pprof.utils.downloader import Git from plumbum.cmd import git minisat_dir = path.join(self.builddir, self.src_dir) with local.cwd(self.builddir): Git(self.src_uri, self.src_dir) with local.cwd(minisat_dir): git("fetch", "origin", "pull/17/head:clang") git("checkout", "clang")
def python_module(git_repo): os.mkdir(PYTHON_MODULE) for file_path, content in PYTHON_PROJECT_CONTENT.items(): open(file_path, 'w').write('\n'.join(content)) git('add', [file for file in PYTHON_PROJECT_CONTENT.keys()]) git('commit', '-m', 'Python project initialisation') yield
def setup(): if not os.path.exists(module_name): os.mkdir(context.module_name) with open(context.tmp_file, 'w') as init_file: init_file.write('\n'.join(context.initial_init_content)) with open(context.requirements, 'w') as req_file: req_file.write('pytest') with local.cwd(local.cwd / context.module_name): git('init') git('remote', 'add', 'origin', 'https://github.com/michaeljoseph/test_app.git')
def github_merge_commit(pull_request_number): from haikunator import Haikunator branch_name = Haikunator().haikunate() commands = [ 'checkout -b {}'.format(branch_name), 'commit --allow-empty -m "Test branch commit message"', 'checkout master', 'merge --no-ff {}'.format(branch_name), 'commit --allow-empty --amend -m ' '"Merge pull request #{} from test_app/{}"'.format( pull_request_number, branch_name ), ] for command in commands: git(shlex.split(command))
def on_github(): """on [github](https://github.com)""" return report_and_raise( 'On GitHub', any(['github.com' in remote for remote in git('remote', '-v').split('\n')]), 'Your package needs to be a GitHub project' )
def configured(git_repo, changes_config_in_tmpdir): changes_config_in_tmpdir.write_text( textwrap.dedent( """\ [changes] auth_token = "foo" """ ) ) Path('.changes.toml').write_text( textwrap.dedent( """\ [changes] releases_directory = "docs/releases" [changes.labels.bug] default = true id = 208045946 url = "https://api.github.com/repos/michaeljoseph/test_app/labels/bug" name = "bug" description = "Bug" color = "f29513" """ ) ) Path('.bumpversion.cfg').write_text( textwrap.dedent( """\ [bumpversion] current_version = 0.0.1 [bumpversion:file:version.txt] """ ) ) for file_to_add in ['.changes.toml', '.bumpversion.cfg']: git('add', file_to_add) git('commit', '-m', 'Add changes configuration files') return str(changes_config_in_tmpdir)
def install_uchroot(self): builddir = settings.CFG["build_dir"].value() with local.cwd(builddir): if not os.path.exists("erlent/.git"): git("clone", "[email protected]:PolyJIT/erlent") else: with local.cwd("erlent"): git("pull", "--rebase") mkdir("-p", "erlent/build") with local.cwd("erlent/build"): from plumbum.cmd import cmake, make, cp cmake("../") make() erlent_path = os.path.abspath(os.path.join(builddir, "erlent", "build")) os.environ["PATH"] = os.path.pathsep.join([erlent_path, os.environ[ "PATH"]]) local.env.update(PATH=os.environ["PATH"]) if not find_package("uchroot"): sys.exit(-1) settings.CFG["env"]["lookup_path"].value().append(erlent_path)
def generate_changelog(context): """Generates an automatic changelog from your commit messages.""" changelog_content = [ '\n## [%s](%s/compare/%s...%s)\n\n' % ( context.new_version, context.repo_url, context.current_version, context.new_version, ) ] git_log_content = None git_log = 'log --oneline --no-merges --no-color'.split(' ') try: git_log_tag = git_log + ['%s..master' % context.current_version] git_log_content = git(git_log_tag) log.debug('content: %s' % git_log_content) except: log.warn('Error diffing previous version, initial release') git_log_content = git(git_log) git_log_content = replace_sha_with_commit_link(context.repo_url, git_log_content) # turn change log entries into markdown bullet points if git_log_content: [ changelog_content.append('* %s\n' % line) if line else line for line in git_log_content[:-1] ] write_new_changelog( context.repo_url, 'CHANGELOG.md', changelog_content, dry_run=context.dry_run ) log.info('Added content to CHANGELOG.md') context.changelog_content = changelog_content
def Git(src_url, tgt_name, tgt_root=None): """ Get a shallow clone of the given respo Args: src_url (str): Git URL of the SOURCE repo. tgt_name (str): Name of the repo folder on disk. tgt_root (str): TARGET folder for the git repo. Defaults to ``CFG["tmpdir"]`` """ if tgt_root is None: tgt_root = CFG["tmp_dir"].value() from os import path from plumbum.cmd import git src_dir = path.join(tgt_root, tgt_name) if not source_required(tgt_name, tgt_root): Copy(src_dir, ".") return git("clone", "--depth", "1", src_url, src_dir) update_hash(tgt_name, tgt_root) Copy(src_dir, ".")
def get_git_hash(from_url): """ Get the git commit hash of HEAD from :from_url. Args: from_url: The file system url of our git repository. Returns: git commit hash of HEAD, or empty string. """ if from_url is None: return "" if not path.exists(from_url): return "" with local.cwd(from_url): return git("rev-parse", "HEAD", retcode=None)
def test_v2_0_0_migration( tmp_path: Path, cloned_template: Path, supported_odoo_version: float, domain_prod, domain_prod_alternatives, domain_test, ): """Test migration to v2.0.0.""" # Construct data dict, removing MISSING values data = { "domain_prod": domain_prod, "domain_prod_alternatives": domain_prod_alternatives, "domain_test": domain_test, "odoo_version": supported_odoo_version, } for key, value in tuple(data.items()): if value is MISSING: data.pop(key, None) # This part makes sense only when v2.0.0 is not yet released with local.cwd(cloned_template): if "v2.0.0" not in git("tag").split(): git("tag", "-d", "test") git("tag", "v2.0.0") with local.cwd(tmp_path): # Copy v1.6.0 copy( src_path=str(cloned_template), vcs_ref="v1.6.0", force=True, answers_file=".custom.copier-answers.yaml", data=data, ) git("config", "commit.gpgsign", "false") git("add", ".") git("commit", "-am", "reformat", retcode=1) git("commit", "-am", "copied from template in v1.6.0") # Update to v2.0.0 copy(answers_file=".custom.copier-answers.yaml", vcs_ref="v2.0.0", force=True) git("add", ".") git("commit", "-am", "reformat", retcode=1) git("commit", "-am", "updated from template in v2.0.0") # Assert domain structure migration answers = yaml.safe_load( Path(".custom.copier-answers.yaml").read_text()) assert "domain_prod" not in answers assert "domain_prod_alternatives" not in answers assert "domain_test" not in answers assert answers["domains_prod"] == { data.get("domain_prod"): data.get("domain_prod_alternatives") or [] } assert answers["domains_staging"] == ([domain_test] if data.get("domain_test") else [])
def test_publish(capsys, configured, answer_prompts): github_merge_commit(111) responses.add( responses.GET, ISSUE_URL, json=PULL_REQUEST_JSON, status=200, content_type='application/json', ) responses.add( responses.GET, LABEL_URL, json=BUG_LABEL_JSON, status=200, content_type='application/json', ) responses.add( responses.POST, RELEASES_URL, json={'upload_url': 'foo'}, status=200, content_type='application/json', ) changes.initialise() stage.stage( draft=False, release_name='Icarus', release_description='The first flight' ) release_notes_path = Path( 'docs/releases/0.0.2-{}-Icarus.md'.format(date.today().isoformat()) ) assert release_notes_path.exists() publish.publish() pre = textwrap.dedent( """\ Staging [fix] release for version 0.0.2... Running: bumpversion --verbose --allow-dirty --no-commit --no-tag patch... Generating Release... Writing release notes to {release_notes_path}... Publishing release 0.0.2... Running: git add version.txt .bumpversion.cfg {release_notes_path}... Running: git commit --message="# 0.0.2 ({release_date}) Icarus """.format( release_notes_path=release_notes_path, release_date=date.today().isoformat() ) ).splitlines() expected_release_notes_content = [ 'The first flight', '## Bug', ' ', '* #111 The title of the pull request', ' ', ] post = textwrap.dedent( """\ "... Running: git tag 0.0.2... Running: git push --tags... Creating GitHub Release... Published release 0.0.2... """ ).splitlines() out, _ = capsys.readouterr() assert pre + expected_release_notes_content + post == out.splitlines() last_commit = git(shlex.split('show --name-only')) expected_files = ['version.txt', '.bumpversion.cfg', release_notes_path] assert [ expected_file for expected_file in expected_files if str(expected_file) in last_commit ] assert '0.0.2' in git(shlex.split('tag --list')) assert release_notes_path.exists() expected_release_notes = [ '# 0.0.2 ({}) Icarus'.format(date.today().isoformat()), 'The first flight', '## Bug', ' ', '* #111 The title of the pull request', ' ', ] assert expected_release_notes == release_notes_path.read_text().splitlines()
def test_commit_hooks_respected(tmp_path_factory): """Commit hooks are taken into account when producing the update diff.""" # Prepare source template v1 src, dst1, dst2 = map(tmp_path_factory.mktemp, ("src", "dst1", "dst2")) with local.cwd(src): build_file_tree( { "copier.yml": """ _tasks: - git init - pre-commit install - pre-commit run -a || true what: grog """, "[[ _copier_conf.answers_file ]].tmpl": """ [[ _copier_answers|to_nice_yaml ]] """, ".pre-commit-config.yaml": r""" repos: - repo: https://github.com/prettier/prettier rev: 2.0.4 hooks: - id: prettier - repo: local hooks: - id: forbidden-files name: forbidden files entry: found forbidden files; remove them language: fail files: "\\.rej$" """, "life.yml.tmpl": """ # Following code should be reformatted by pre-commit after copying Line 1: hello Line 2: [[ what ]] Line 3: bye """, } ) git("init") git("add", ".") git("commit", "-m", "commit 1") git("tag", "v1") # Copy source template copy(src_path=str(src), dst_path=dst1, force=True) with local.cwd(dst1): life = Path("life.yml") git("add", ".") # 1st commit fails because pre-commit reformats life.yml git("commit", "-am", "failed commit", retcode=1) # 2nd commit works because it's already formatted git("commit", "-am", "copied v1") assert life.read_text() == dedent( """\ # Following code should be reformatted by pre-commit after copying Line 1: hello Line 2: grog Line 3: bye """ ) # Evolve source template to v2 with local.cwd(src): build_file_tree( { "life.yml.tmpl": """ # Following code should be reformatted by pre-commit after copying Line 1: hello world Line 2: grow up Line 3: [[ what ]] Line 4: grow old Line 5: bye bye world """, } ) git("init") git("add", ".") git("commit", "-m", "commit 2") git("tag", "v2") # Update subproject to v2 copy(dst_path=dst1, force=True) with local.cwd(dst1): git("commit", "-am", "copied v2") assert life.read_text() == dedent( """\ # Following code should be reformatted by pre-commit after copying Line 1: hello world Line 2: grow up Line 3: grog Line 4: grow old Line 5: bye bye world """ ) # No .rej files created (update diff was smart) assert not git("status", "--porcelain") # Subproject evolves life.write_text( dedent( """\ Line 1: hello world Line 2: grow up Line 2.5: make friends Line 3: grog Line 4: grow old Line 4.5: no more work Line 5: bye bye world """ ) ) git("commit", "-am", "subproject is evolved") # A new subproject appears, which is a shallow clone of the 1st one. # Using file:// prefix to allow local shallow clones. git("clone", "--depth=1", f"file://{dst1}", dst2) with local.cwd(dst2): # Subproject re-updates just to change some values copy(data={"what": "study"}, force=True) git("commit", "-am", "re-updated to change values after evolving") # Subproject evolution was respected up to sane possibilities. # In an ideal world, this file would be exactly the same as what's written # a few lines above, just changing "grog" for "study". However, that's nearly # impossible to achieve, because each change hunk needs at least 1 line of # context to let git apply that patch smartly, and that context couldn't be # found because we changed data when updating, so the sanest thing we can # do is to provide a .rej file to notify those # unresolvable diffs. OTOH, some other changes are be applied. # If some day you are able to produce that ideal result, you should be # happy to modify these asserts. assert life.read_text() == dedent( """\ Line 1: hello world Line 2: grow up Line 3: study Line 4: grow old Line 4.5: no more work Line 5: bye bye world """ ) # This time a .rej file is unavoidable assert Path(f"{life}.rej").is_file()
def git_init(message="hello world"): git("init") git("config", "user.name", "Copier Test") git("config", "user.email", "test@copier") git("add", ".") git("commit", "-m", message)
def test_new_version_uses_subdirectory(tmp_path_factory): # Template in v1 doesn't have a _subdirectory; # in v2 it moves all things into a subdir and adds that key to copier.yml. # Some files change. Downstream project has evolved too. Does that work as expected? template_path = tmp_path_factory.mktemp("subdirectory_template") project_path = tmp_path_factory.mktemp("subdirectory_project") # First, create the template with an initial README with local.cwd(template_path): with open("README.md", "w") as fd: fd.write("upstream version 1\n") with open("[[_copier_conf.answers_file]].tmpl", "w") as fd: fd.write("[[_copier_answers|to_nice_yaml]]\n") git_init("hello template") git("tag", "v1") # Generate the project a first time, assert the README exists copier.copy(str(template_path), project_path, force=True) assert (project_path / "README.md").exists() assert "_commit: v1" in (project_path / ".copier-answers.yml").read_text() # Start versioning the generated project with local.cwd(project_path): git_init("hello project") # After first commit, change the README, commit again with open("README.md", "w") as fd: fd.write("downstream version 1\n") git("commit", "-am", "updated readme") # Now change the template with local.cwd(template_path): # Update the README with open("README.md", "w") as fd: fd.write("upstream version 2\n") # Create a subdirectory, move files into it os.mkdir("subdir") os.rename("README.md", "subdir/README.md") os.rename( "[[_copier_conf.answers_file]].tmpl", "subdir/[[_copier_conf.answers_file]].tmpl", ) # Add the subdirectory option to copier.yml with open("copier.yml", "w") as fd: fd.write("_subdirectory: subdir\n") # Commit the changes git("add", ".", "-A") git("commit", "-m", "use a subdirectory now") git("tag", "v2") # Finally, update the generated project copier.copy(dst_path=project_path, force=True) assert "_commit: v2" in (project_path / ".copier-answers.yml").read_text() # Assert that the README still exists, and was force updated to "upstream version 2" assert (project_path / "README.md").exists() with (project_path / "README.md").open() as fd: assert fd.read() == "upstream version 2\n" # Also assert the subdirectory itself was not rendered assert not (project_path / "subdir").exists()
def commit_files(self): # fixme use GitPorcelainPorcelain with local.cwd(self.projectPath): log.info(cmd.git("commit", "-m", "new build"))
def test_pre_migration_modifies_answers(tmp_path_factory): """Test support for answers modifications in pre-migrations.""" template = tmp_path_factory.mktemp("template") subproject = tmp_path_factory.mktemp("subproject") # v1 of template asks for a favourite song and writes it to songs.yaml with local.cwd(template): build_file_tree({ "[[ _copier_conf.answers_file ]].tmpl": "[[ _copier_answers|to_nice_yaml ]]", "copier.yml": """\ best_song: la vie en rose """, "songs.yaml.tmpl": "- [[ best_song ]]", }) git("init") git("add", ".") git("commit", "-m1") git("tag", "v1") # User copies v1 template into subproject with local.cwd(subproject): copy(src_path=str(template), force=True) answers = yaml.safe_load(Path(".copier-answers.yml").read_text()) assert answers["_commit"] == "v1" assert answers["best_song"] == "la vie en rose" assert yaml.safe_load( Path("songs.yaml").read_text()) == ["la vie en rose"] git("init") git("add", ".") git("commit", "-m1") with local.cwd(template): build_file_tree({ # v2 of template supports multiple songs, has a different default # and includes a data format migration script "copier.yml": """\ best_song_list: default: [paranoid android] _migrations: - version: v2 before: - - python3 - -c - | import sys, yaml, pathlib answers_path = pathlib.Path(*sys.argv[1:]) answers = yaml.safe_load(answers_path.read_text()) answers["best_song_list"] = [answers.pop("best_song")] answers_path.write_text(yaml.safe_dump(answers)) - "[[ _copier_conf.dst_path ]]" - "[[ _copier_conf.answers_file ]]" """, "songs.yaml.tmpl": "[[ best_song_list|to_nice_yaml ]]", }) git("add", ".") git("commit", "-m2") git("tag", "v2") # User updates subproject to v2 template with local.cwd(subproject): copy(force=True) answers = yaml.safe_load(Path(".copier-answers.yml").read_text()) assert answers["_commit"] == "v2" assert "best_song" not in answers assert answers["best_song_list"] == ["la vie en rose"] assert yaml.safe_load( Path("songs.yaml").read_text()) == ["la vie en rose"]
def test_v1_5_3_migration(tmp_path: Path, cloned_template: Path, supported_odoo_version: float): """Test migration to v1.5.3.""" auto_addons = tmp_path / "odoo" / "auto" / "addons" # This part makes sense only when v1.5.3 is not yet released with local.cwd(cloned_template): if "v1.5.3" not in git("tag").split(): git("tag", "-d", "test") git("tag", "v1.5.3") with local.cwd(tmp_path): # Copy v1.5.2 copy(src_path=str(cloned_template), vcs_ref="v1.5.2", force=True) assert not auto_addons.exists() git("add", ".") git("commit", "-am", "reformat", retcode=1) git("commit", "-am", "copied from template in v1.5.2") # Update to v1.5.3 copy(vcs_ref="v1.5.3", force=True) assert not auto_addons.exists() invoke("develop") assert auto_addons.is_dir() # odoo/auto/addons dir must be writable (auto_addons / "sample").touch()
def has_signing_key(context): return 'signingkey' in git('config', '-l')
def local_repo(tmp_path, branch): local_path = (tmp_path / "local").resolve() local_path.mkdir() with local.cwd(local_path): git("clone", "--branch", branch, tmp_path / "remote", local_path) yield local_path
def test_prereleases(tmp_path: Path): """Test prereleases support for copying and updating.""" src, dst = tmp_path / "src", tmp_path / "dst" src.mkdir() with local.cwd(src): # Build template in v1.0.0 build_file_tree({ "version.txt": "v1.0.0", "[[ _copier_conf.answers_file ]].tmpl": "[[_copier_answers|to_nice_yaml]]", "copier.yaml": """ _migrations: - version: v1.9 before: - [python, -c, "import pathlib; pathlib.Path('v1.9').touch()"] - version: v2.dev0 before: - [python, -c, "import pathlib; pathlib.Path('v2.dev0').touch()"] - version: v2.dev2 before: - [python, -c, "import pathlib; pathlib.Path('v2.dev2').touch()"] - version: v2.a1 before: - [python, -c, "import pathlib; pathlib.Path('v2.a1').touch()"] - version: v2.a2 before: - [python, -c, "import pathlib; pathlib.Path('v2.a2').touch()"] """, }) git("init") git("add", ".") git("commit", "-mv1") git("tag", "v1.0.0") # Evolve template to v2.0.0.dev1 build_file_tree({"version.txt": "v2.0.0.dev1"}) git("commit", "-amv2dev1") git("tag", "v2.0.0.dev1") # Evolve template to v2.0.0.alpha1 build_file_tree({"version.txt": "v2.0.0.alpha1"}) git("commit", "-amv2a1") git("tag", "v2.0.0.alpha1") # Copying with use_prereleases=False copies v1 copy(src_path=str(src), dst_path=dst, force=True) answers = yaml.safe_load((dst / ".copier-answers.yml").read_text()) assert answers["_commit"] == "v1.0.0" assert (dst / "version.txt").read_text() == "v1.0.0" assert not (dst / "v1.9").exists() assert not (dst / "v2.dev0").exists() assert not (dst / "v2.dev2").exists() assert not (dst / "v2.a1").exists() assert not (dst / "v2.a2").exists() with local.cwd(dst): # Commit subproject git("init") git("add", ".") git("commit", "-mv1") # Update it without prereleases; nothing changes copy(force=True) assert not git("status", "--porcelain") assert not (dst / "v1.9").exists() assert not (dst / "v2.dev0").exists() assert not (dst / "v2.dev2").exists() assert not (dst / "v2.a1").exists() assert not (dst / "v2.a2").exists() # Update it with prereleases copy(dst_path=dst, force=True, use_prereleases=True) answers = yaml.safe_load((dst / ".copier-answers.yml").read_text()) assert answers["_commit"] == "v2.0.0.alpha1" assert (dst / "version.txt").read_text() == "v2.0.0.alpha1" assert (dst / "v1.9").exists() assert (dst / "v2.dev0").exists() assert (dst / "v2.dev2").exists() assert (dst / "v2.a1").exists() assert not (dst / "v2.a2").exists() # It should fail if downgrading with pytest.raises(UserMessageError): copy(dst_path=dst, force=True)
def main(): srcdir = self.prefix / "BRAINSTools" blddir = self.prefix / "BRAINSTools-build" logging.info("Get source:") if not srcdir.exists(): repo = 'https://github.com/BRAINSia/BRAINSTools.git' git("clone", repo, srcdir) else: with local.cwd(srcdir): git("fetch", "origin") if self.githash is not None: git("checkout", args.githash) clone_hash = git("rev-parse", "--short", "HEAD")[:-1] # remove trailing \n logging.info("Build code:") blddir.mkdir() with local.cwd(blddir): cmake( srcdir, "-DBRAINSTools_INSTALL_DEVELOPMENT=OFF", "-DBRAINSTools_MAX_TEST_LEVEL=0", "-DBRAINSTools_SUPERBUILD=ON", "-DBRAINSTools_USE_QT=OFF", "-DBRAINS_DEBUG_IMAGE_WRITE=OFF", "-DBUILD_STYLE_UTILS=OFF", "-DBUILD_TESTING=OFF", "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_COLOR_MAKEFILE=ON", "-DCMAKE_EXE_LINKER_FLAGS=' '", "-DCMAKE_EXE_LINKER_FLAGS_DEBUG=", "-DCMAKE_EXE_LINKER_FLAGS_MINSIZEREL=", "-DCMAKE_EXE_LINKER_FLAGS_RELEASE=", "-DCMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO=", "-DCMAKE_EXPORT_COMPILE_COMMANDS=OFF", "-DCMAKE_INSTALL_PREFIX:PATH=/usr/local", "-DCMAKE_MODULE_LINKER_FLAGS=' '", "-DCMAKE_MODULE_LINKER_FLAGS_DEBUG=", "-DCMAKE_MODULE_LINKER_FLAGS_MINSIZEREL=", "-DCMAKE_MODULE_LINKER_FLAGS_RELEASE=", "-DCMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO=", "-DCMAKE_PROJECT_NAME:STATIC=SuperBuild_BRAINSTools", "-DCMAKE_SHARED_LINKER_FLAGS=' '", "-DCMAKE_SHARED_LINKER_FLAGS_DEBUG=", "-DCMAKE_SHARED_LINKER_FLAGS_MINSIZEREL=", "-DCMAKE_SHARED_LINKER_FLAGS_RELEASE=", "-DCMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO=", "-DCMAKE_SKIP_INSTALL_RPATH=NO", "-DCMAKE_SKIP_RPATH=NO", "-DCMAKE_STATIC_LINKER_FLAGS=", "-DCMAKE_STATIC_LINKER_FLAGS_DEBUG=", "-DCMAKE_STATIC_LINKER_FLAGS_MINSIZEREL=", "-DCMAKE_STATIC_LINKER_FLAGS_RELEASE=", "-DCMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO=", "-DCMAKE_USE_RELATIVE_PATHS=OFF", "-DCMAKE_VERBOSE_MAKEFILE=FALSE", "-DCOVERAGE_EXTRA_FLAGS=-l", "-DCTEST_SUBMIT_RETRY_COUNT=3", "-DCTEST_SUBMIT_RETRY_DELAY=5", "-DDART_TESTING_TIMEOUT=1500", "-DEXTERNAL_PROJECT_BUILD_TYPE=Release", "-DFORCE_EXTERNAL_BUILDS=OFF", "-DITK_VERSION_MAJOR=4", "-DSuperBuild_BRAINSTools_BUILD_DICOM_SUPPORT=ON", "-DSuperBuild_BRAINSTools_USE_CTKAPPLAUNCHER=OFF", "-DSuperBuild_BRAINSTools_USE_GIT_PROTOCOL=ON", "-DUSE_ANTS=ON", "-DUSE_AutoWorkup=OFF", "-DUSE_BRAINSABC=OFF", "-DUSE_BRAINSConstellationDetector=OFF", "-DUSE_BRAINSContinuousClass=OFF", "-DUSE_BRAINSCreateLabelMapFromProbabilityMaps=OFF", "-DUSE_BRAINSCut=OFF", "-DUSE_BRAINSDWICleanup=OFF", "-DUSE_BRAINSDemonWarp=OFF", "-DUSE_BRAINSFit=OFF", "-DUSE_BRAINSInitializedControlPoints=OFF", "-DUSE_BRAINSLabelStats=OFF", "-DUSE_BRAINSLandmarkInitializer=OFF", "-DUSE_BRAINSMultiModeSegment=OFF", "-DUSE_BRAINSMultiSTAPLE=OFF", "-DUSE_BRAINSMush=OFF", "-DUSE_BRAINSPosteriorToContinuousClass=OFF", "-DUSE_BRAINSROIAuto=OFF", "-DUSE_BRAINSResample=OFF", "-DUSE_BRAINSSnapShotWriter=OFF", "-DUSE_BRAINSStripRotation=OFF", "-DUSE_BRAINSSurfaceTools=OFF", "-DUSE_BRAINSTalairach=OFF", "-DUSE_BRAINSTransformConvert=OFF", "-DUSE_ConvertBetweenFileFormats=ON", "-DUSE_DWIConvert=ON", "-DUSE_DebugImageViewer=OFF", "-DUSE_GTRACT=OFF", "-DUSE_ICCDEF=OFF", "-DUSE_ImageCalculator=OFF", "-DUSE_ReferenceAtlas=OFF", "-DUSE_SYSTEM_DCMTK=OFF", "-DUSE_SYSTEM_ITK=OFF", "-DUSE_SYSTEM_SlicerExecutionModel=OFF", "-DUSE_SYSTEM_VTK=OFF", "-DVTK_GIT_REPOSITORY=git://vtk.org/VTK.git") make['all'] & FG outbin = self.prefix / 'BRAINSTools-bin-' + clone_hash (blddir / 'bin').move(outbin)
def test_pre_commit_in_subproject(tmp_path: Path, cloned_template: Path, supported_odoo_version: float): """Test that .pre-commit-config.yaml has some specific settings fine.""" copy( str(cloned_template), str(tmp_path), vcs_ref="HEAD", force=True, data={"odoo_version": supported_odoo_version}, ) # Make sure the template was correctly rendered pre_commit_config = yaml.safe_load( (tmp_path / ".pre-commit-config.yaml").read_text()) is_py3 = supported_odoo_version >= 11 found = 0 should_find = 1 for repo in pre_commit_config["repos"]: if repo["repo"] == "https://github.com/pre-commit/pre-commit-hooks": found += 1 if is_py3: assert {"id": "debug-statements"} in repo["hooks"] assert { "id": "fix-encoding-pragma", "args": ["--remove"] } in repo["hooks"] else: assert {"id": "debug-statements"} not in repo["hooks"] assert { "id": "fix-encoding-pragma", "args": ["--remove"] } not in repo["hooks"] assert {"id": "fix-encoding-pragma"} in repo["hooks"] assert found == should_find # Make sure it reformats correctly some files with local.cwd(tmp_path / "odoo" / "custom" / "src" / "private"): git("add", "-A") git("commit", "-m", "hello world", retcode=1) git("commit", "-am", "hello world") manifest = "__manifest__" if is_py3 else "__openerp__" generate_test_addon("test_module", supported_odoo_version, ugly=True) git("add", "-A") git("commit", "-m", "added test_module", retcode=1) git("commit", "-am", "added test_module") expected_samples = { f"test_module/{manifest}.py": f"""\ {"{"} "name": "test_module", "license": "AGPL-3", "version": "{supported_odoo_version}.1.0.0", "depends": ["base"], "installable": True, "auto_install": False, {"}"} """, "test_module/__init__.py": """\ from . import models """, "test_module/models/__init__.py": """\ from . import res_partner """, "test_module/models/res_partner.py": '''\ import io import sys from logging import getLogger from os.path import join from requests import get import odoo from odoo import models _logger = getLogger(__name__) class ResPartner(models.Model): _inherit = "res.partner" def some_method(self, test): """some weird docstring""" _logger.info(models, join, get, io, sys, odoo) ''', } for path, content in expected_samples.items(): content = dedent(content) if not is_py3 and path.endswith(".py"): content = f"# -*- coding: utf-8 -*-\n{content}" assert Path(path).read_text() == content # Make sure it doesn't fail for incorrect module version when addon not installable with local.cwd(tmp_path / "odoo" / "custom" / "src" / "private"): # Bump version in test module and set as not installable generate_test_addon("test_module", supported_odoo_version + 1, installable=False) git("add", "-A") # First commit will add new module to the exclude list in pre-commit git("commit", "-m", "start migration of test_module", retcode=1) # Module should now be ignored by pre-commit and give no problems in commit git("commit", "-am", "start migration of test_module") # Load pre-commit config with open(tmp_path / ".pre-commit-config.yaml", "r") as fd: pre_commit_config = yaml.safe_load(fd.read()) assert "^odoo/custom/src/private/test_module/|" in pre_commit_config[ "exclude"] # Make sure uninstallable addon was ignored by pre-commit pre_commit("run", "-a") assert "test_module" not in git("status", "--porcelain") # It should still fail for installable addon with bad manifest with local.cwd(tmp_path / "odoo" / "custom" / "src" / "private"): # Mark test module as installable again generate_test_addon("test_module", supported_odoo_version + 1, installable=True) git("add", "-A") # First commit will remove test module to the exclude list in pre-commit git("commit", "-m", "Mark test module as installable again", retcode=1) # Commit should fail for incorrect version with pytest.raises(ProcessExecutionError): git("commit", "-am", "Mark test_module as installable again") # Load pre-commit config with open(tmp_path / ".pre-commit-config.yaml", "r") as fd: pre_commit_config = yaml.safe_load(fd.read()) assert ("^odoo/custom/src/private/test_module/|" not in pre_commit_config["exclude"])
def test_code_workspace_file(tmp_path: Path, cloned_template: Path, supported_odoo_version: float): """The file is generated as expected.""" copy( str(cloned_template), str(tmp_path), vcs_ref="HEAD", force=True, data={"odoo_version": supported_odoo_version}, ) assert (tmp_path / f"doodba.{tmp_path.name}.code-workspace").is_file() (tmp_path / f"doodba.{tmp_path.name}.code-workspace").rename( tmp_path / "doodba.other1.code-workspace") with local.cwd(tmp_path / "odoo" / "custom" / "src" / "private"): # Generate generic addon path is_py3 = supported_odoo_version >= 11 manifest = "__manifest__" if is_py3 else "__openerp__" build_file_tree({ f"test_module_static/{manifest}.py": f"""\ {"{"} 'name':'test module','license':'AGPL-3', 'version':'{supported_odoo_version}.1.0.0', 'installable': True, 'auto_install': False {"}"} """, "test_module_static/static/index.html": """\ <html> </html> """, }) with local.cwd(tmp_path): invoke("write-code-workspace-file") assert (tmp_path / "doodba.other1.code-workspace").is_file() assert not (tmp_path / f"doodba.{tmp_path.name}.code-workspace").is_file() # Do a stupid and dirty git clone to check it's sorted fine git("clone", cloned_template, Path("odoo", "custom", "src", "zzz")) # "Clone" a couple more repos, including odoo to check order git("clone", cloned_template, Path("odoo", "custom", "src", "aaa")) git("clone", cloned_template, Path("odoo", "custom", "src", "bbb")) git("clone", cloned_template, Path("odoo", "custom", "src", "odoo")) invoke("write-code-workspace-file", "-c", "doodba.other2.code-workspace") assert not (tmp_path / f"doodba.{tmp_path.name}.code-workspace").is_file() assert (tmp_path / "doodba.other1.code-workspace").is_file() assert (tmp_path / "doodba.other2.code-workspace").is_file() with (tmp_path / "doodba.other2.code-workspace").open() as fp: workspace_definition = json.load(fp) # Check workspace folder definition and order assert workspace_definition["folders"] == [ { "path": "odoo/custom/src/aaa" }, { "path": "odoo/custom/src/bbb" }, { "path": "odoo/custom/src/zzz" }, { "path": "odoo/custom/src/odoo" }, { "path": "odoo/custom/src/private" }, { "name": f"doodba.{tmp_path.name}", "path": "." }, ] # Firefox debugger configuration url = f"http://localhost:{supported_odoo_version:.0f}069/test_module_static/static/" path = "${workspaceFolder:private}/test_module_static/static/" firefox_configuration = next( conf for conf in workspace_definition["launch"]["configurations"] if conf["type"] == "firefox") assert { "url": url, "path": path } in firefox_configuration["pathMappings"] # Chrome debugger configuration chrome_configuration = next( conf for conf in workspace_definition["launch"]["configurations"] if conf["type"] == "chrome") assert chrome_configuration["pathMapping"][url] == path
def cloned_template(tmp_path_factory): """This repo cloned to a temporary destination. The clone will include dirty changes, and it will have a 'test' tag in its HEAD. It returns the local `Path` to the clone. """ patches = [git("diff", "--cached"), git("diff")] with tmp_path_factory.mktemp("cloned_template_") as dirty_template_clone: git("clone", "--recurse-submodules", ".", dirty_template_clone) with local.cwd(dirty_template_clone): git("config", "commit.gpgsign", "false") for patch in patches: if patch: (git["apply", "--reject"] << patch)() git("add", ".") git( "commit", "--author=Test<test@test>", "--message=dirty changes", "--no-verify", ) git("tag", "--force", "test") yield dirty_template_clone
def parsed_repo(self): with local.cwd(local.cwd / self.module_name): return parse(git('config --get remote.origin.url'.split(' ')))
def _args(): parser = ArgumentParser() args = Dodo.parse_args(parser) return args if Dodo.is_main(__name__): args = _args() src_dir = Dodo.get_config('/ROOT/src_dir') for repo in (os.listdir(src_dir) + ['.']): repo_dir = os.path.join(src_dir, repo) if os.path.exists(os.path.join(repo_dir, '.git')): with local.cwd(repo_dir): status = git('status') files_to_commit = ('nothing to commit, working directory clean' not in status) and ( 'nothing to commit, working tree clean' not in status) diverged = ('Your branch is up-to-date with' not in status) and ( 'Your branch is up to date with' not in status) if files_to_commit or diverged: print(bordered(repo)) print(git('rev-parse', '--abbrev-ref', 'HEAD')[:-1]) if files_to_commit: print("Files to commit") if diverged: print("Branch has diverged")
cp(source_path + "/Procfile", project_path) cp(source_path + "/runtime.txt", project_path) with colors.orchid: print "========== Installing Vagrant environment ==========" cp(source_path + "/Vagrantfile", project_path) # Install provisioning script. cp(source_path + "/provision.sh", project_path) # Installing requirements.txt cp(source_path + "/requirements.txt", project_path) cp(source_path + "/.bashrc", project_path) cp(source_path + "/zeus.sh", project_path) with colors.orchid: print "========== Setting up bare README.md ==========" cp(source_path + "/readme.txt", project_path + "/README.md") # Change current working directory to project directory. local.cwd = project_path with colors.orchid: print "========== Initialising local git repository ==========" git("init") with colors.orchid: print "========== Launching vagrant up ==========" vagrant["up"] & FG with colors.orchid: print "========== Initialising vagrant ssh session ==========" vagrant["ssh"] & FG
def test_migrations_and_tasks(tmpdir: py.path.local): """Check migrations and tasks are run properly.""" # Convert demo_migrations in a git repository with 2 versions git_src, tmp_path = tmpdir / "src", tmpdir / "tmp_path" copytree(SRC, git_src) with local.cwd(git_src): git("init") git("config", "user.name", "Copier Test") git("config", "user.email", "test@copier") git("add", ".") git("commit", "-m1") git("tag", "v1.0.0") git("commit", "--allow-empty", "-m2") git("tag", "v2.0") # Copy it in v1 copy(src_path=str(git_src), dst_path=str(tmp_path), vcs_ref="v1.0.0") # Check copy was OK assert (tmp_path / "created-with-tasks.txt").read() == "task 1\ntask 2\n" assert not (tmp_path / "delete-in-tasks.txt").exists() assert (tmp_path / "delete-in-migration-v2.txt").isfile() assert not (tmp_path / "migrations.py").exists() assert not (tmp_path / "tasks.sh").exists() assert not glob(str(tmp_path / "*-before.txt")) assert not glob(str(tmp_path / "*-after.txt")) answers = yaml.safe_load((tmp_path / ".copier-answers.yml").read()) assert answers == {"_commit": "v1.0.0", "_src_path": str(git_src)} # Save changes in downstream repo with local.cwd(tmp_path): git("add", ".") git("config", "user.name", "Copier Test") git("config", "user.email", "test@copier") git("commit", "-m1") # Update it to v2 copy(dst_path=str(tmp_path), force=True) # Check update was OK assert (tmp_path / "created-with-tasks.txt").read() == "task 1\ntask 2\n" * 2 assert not (tmp_path / "delete-in-tasks.txt").exists() assert not (tmp_path / "delete-in-migration-v2.txt").exists() assert not (tmp_path / "migrations.py").exists() assert not (tmp_path / "tasks.sh").exists() assert (tmp_path / "v1.0.0-v2-v2.0-before.json").isfile() assert (tmp_path / "v1.0.0-v2-v2.0-after.json").isfile() answers = yaml.safe_load((tmp_path / ".copier-answers.yml").read()) assert answers == {"_commit": "v2.0", "_src_path": str(git_src)}
def commit_all(message): git("add", "-A") git("commit", "-am", message)
def update_diff(conf: ConfigData): # Ensure local repo is clean if vcs.is_git_repo_root(conf.dst_path): with local.cwd(conf.dst_path): if git("status", "--porcelain"): raise UserMessageError( "Destination repository is dirty; cannot continue. " "Please commit or stash your local changes and retry.") last_answers = load_answersfile_data(conf.dst_path, conf.answers_file) # Copy old template into a temporary destination with tempfile.TemporaryDirectory( prefix=f"{__name__}.update_diff.") as dst_temp: copy( dst_path=dst_temp, data=last_answers, force=True, quiet=True, skip=False, src_path=conf.original_src_path, vcs_ref=conf.old_commit, ) # Extract diff between temporary destination and real destination with local.cwd(dst_temp): git("init", retcode=None) git("add", ".") git("config", "user.name", "Copier") git("config", "user.email", "copier@copier") # 1st commit could fail if any pre-commit hook reformats code git("commit", "--allow-empty", "-am", "dumb commit 1", retcode=None) git("commit", "--allow-empty", "-am", "dumb commit 2") git("config", "--unset", "user.name") git("config", "--unset", "user.email") git("remote", "add", "real_dst", conf.dst_path) git("fetch", "real_dst", "HEAD") diff_cmd = git["diff", "--unified=1", "HEAD...FETCH_HEAD"] try: diff = diff_cmd("--inter-hunk-context=-1") except ProcessExecutionError: print( colors.warn | "Make sure Git >= 2.24 is installed to improve updates.") diff = diff_cmd("--inter-hunk-context=0") # Run pre-migration tasks renderer = Renderer(conf) run_tasks(conf, renderer, get_migration_tasks(conf, "before")) # Import possible answers migration conf = conf.copy( update={ "data_from_answers_file": load_answersfile_data(conf.dst_path, conf.answers_file) }) # Do a normal update in final destination copy_local(conf) # Try to apply cached diff into final destination with local.cwd(conf.dst_path): apply_cmd = git["apply", "--reject", "--exclude", conf.answers_file] for skip_pattern in conf.skip_if_exists: apply_cmd = apply_cmd["--exclude", skip_pattern] (apply_cmd << diff)(retcode=None) # Run post-migration tasks run_tasks(conf, renderer, get_migration_tasks(conf, "after"))
def make_config( src_path: OptStr = None, dst_path: str = ".", *, answers_file: OptStr = None, data: OptAnyByStrDict = None, exclude: OptStrSeq = None, skip_if_exists: OptStrSeq = None, tasks: OptStrSeq = None, envops: OptAnyByStrDict = None, extra_paths: OptStrSeq = None, pretend: OptBool = None, force: OptBool = None, skip: OptBool = None, quiet: OptBool = None, cleanup_on_error: OptBool = None, vcs_ref: OptStr = None, subdirectory: OptStr = None, **kwargs, ) -> ConfigData: """Provides the configuration object, merged from the different sources. The order of precedence for the merger of configuration objects is: function_args > user_data > defaults. """ # Merge answer sources in the order of precedence answers_data = DEFAULT_DATA.copy() answers_data.update(load_answersfile_data(dst_path, answers_file)) answers_data.update(data or {}) _metadata = {} if "_commit" in answers_data: _metadata["old_commit"] = answers_data["_commit"] # Detect original source if running in update mode if src_path is None: try: src_path = answers_data["_src_path"] except KeyError: raise NoSrcPathError( "No copier answers file found, or it didn't include " "original template information (_src_path). " "Run `copier copy` instead.") _metadata["original_src_path"] = src_path if src_path: repo = vcs.get_repo(src_path) if repo: src_path = vcs.clone(repo, vcs_ref or "HEAD") vcs_ref = vcs_ref or vcs.checkout_latest_tag(src_path) with local.cwd(src_path): _metadata["commit"] = git("describe", "--tags", "--always").strip() # Obtain config and query data, asking the user if needed file_data = load_config_data(src_path, quiet=True) try: verify_minimum_version(file_data["_min_copier_version"]) except KeyError: pass config_data, questions_data = filter_config(file_data) config_data.update(_metadata) del _metadata args = {k: v for k, v in locals().items() if v is not None and v != []} env_ops = EnvOps(**config_data.get("envops", {})) config_data["data"] = query_user_data(questions_data, answers_data, not force, env_ops) args = {**config_data, **args} args["envops"] = env_ops args["data"].update(config_data["data"]) return ConfigData(**args)
def test_new_version_changes_subdirectory(tmp_path_factory): # Template in v3 changes from one subdirectory to another. # Some file evolves also. Sub-project evolves separately. # Sub-project is updated. Does that work as expected? template_path = tmp_path_factory.mktemp("subdirectory_template") project_path = tmp_path_factory.mktemp("subdirectory_project") # First, create the template with an initial subdirectory and README inside it with local.cwd(template_path): os.mkdir("subdir1") with open("subdir1/README.md", "w") as fd: fd.write("upstream version 1\n") with open("subdir1/[[_copier_conf.answers_file]].tmpl", "w") as fd: fd.write("[[_copier_answers|to_nice_yaml]]\n") # Add the subdirectory option to copier.yml with open("copier.yml", "w") as fd: fd.write("_subdirectory: subdir1\n") git_init("hello template") # Generate the project a first time, assert the README exists copier.copy(str(template_path), project_path, force=True) assert (project_path / "README.md").exists() # Start versioning the generated project with local.cwd(project_path): git_init("hello project") # After first commit, change the README, commit again with open("README.md", "w") as fd: fd.write("downstream version 1\n") git("commit", "-am", "updated readme") # Now change the template with local.cwd(template_path): # Update the README with open("subdir1/README.md", "w") as fd: fd.write("upstream version 2\n") # Rename the subdirectory os.rename("subdir1", "subdir2") # Update copier.yml to reflect this change with open("copier.yml", "w") as fd: fd.write("_subdirectory: subdir2\n") # Commit the changes git("add", ".", "-A") git("commit", "-m", "changed from subdir1 to subdir2") # Finally, update the generated project copier.copy(str(template_path), project_path, force=True, skip_if_exists=["README.md"]) # Assert that the README still exists, and was NOT force updated assert (project_path / "README.md").exists() with (project_path / "README.md").open() as fd: assert fd.read() == "downstream version 1\n" # Also assert the subdirectories themselves were not rendered assert not (project_path / "subdir1").exists() assert not (project_path / "subdir2").exists()
def is_git_bundle(path: Path) -> bool: """Indicate if a path is a valid git bundle.""" with TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname: with local.cwd(dirname): git("init") return bool(git["bundle", "verify", path] & TF)
from dodo_commands import Dodo from dodo_commands.framework.util import bordered def _args(): parser = ArgumentParser() parser.add_argument('--checkout') parser.add_argument('--prune', action='store_true') args = Dodo.parse_args(parser) return args if Dodo.is_main(__name__): args = _args() src_dir = Dodo.get_config('/ROOT/src_dir') for repo in (os.listdir(src_dir) + ['.']): repo_dir = os.path.join(src_dir, repo) if os.path.exists(os.path.join(repo_dir, '.git')): with local.cwd(repo_dir): if args.prune: print(git('remote', 'prune', 'origin')) print(bordered(repo)) if args.checkout: try: git('checkout', args.checkout) except: print('Could not checkout to %s' % args.checkout) pass print(git('rev-parse', '--abbrev-ref', 'HEAD'))
def test_updatediff(tmpdir): tmp_path = Path(tmpdir) target = tmp_path / "target" readme = target / "README.txt" answers = target / ".copier-answers.yml" commit = git["commit", "--all"] # Run copier 1st time, with specific tag CopierApp.invoke( "copy", str(REPO_BUNDLE_PATH), str(target), force=True, vcs_ref="v0.0.1" ) # Check it's copied OK assert answers.read_text() == dedent( f""" # Changes here will be overwritten by Copier _commit: v0.0.1 _src_path: {REPO_BUNDLE_PATH} author_name: Guybrush project_name: to become a pirate """ ) assert readme.read_text() == dedent( """ Let me introduce myself. My name is Guybrush, and my project is to become a pirate. Thanks for your attention. """ ) # Init destination as a new independent git repo with local.cwd(target): git("init") # Configure git in case you're running in CI git("config", "user.name", "Copier Test") git("config", "user.email", "test@copier") # Commit changes git("add", ".") commit("-m", "hello world") # Emulate the user modifying the README by hand with open(readme, "w") as readme_fd: readme_fd.write( dedent( """ Let me introduce myself. My name is Guybrush, and my project is to become a pirate. Thanks for your grog. """ ) ) commit("-m", "I prefer grog") # Update target to latest tag and check it's updated in answers file CopierApp.invoke(force=True) assert answers.read_text() == dedent( f""" # Changes here will be overwritten by Copier _commit: v0.0.2 _src_path: {REPO_BUNDLE_PATH} author_name: Guybrush project_name: to become a pirate """ ) # Check migrations were executed properly assert not (target / "before-v0.0.1").is_file() assert not (target / "after-v0.0.1").is_file() assert (target / "before-v0.0.2").is_file() assert (target / "after-v0.0.2").is_file() (target / "before-v0.0.2").unlink() (target / "after-v0.0.2").unlink() assert not (target / "before-v1.0.0").is_file() assert not (target / "after-v1.0.0").is_file() commit("-m", "Update template to v0.0.2") # Update target to latest commit, which is still untagged CopierApp.invoke(force=True, vcs_ref="HEAD") # Check no new migrations were executed assert not (target / "before-v0.0.1").is_file() assert not (target / "after-v0.0.1").is_file() assert not (target / "before-v0.0.2").is_file() assert not (target / "after-v0.0.2").is_file() assert not (target / "before-v1.0.0").is_file() assert not (target / "after-v1.0.0").is_file() # Check it's updated OK assert answers.read_text() == dedent( f""" # Changes here will be overwritten by Copier _commit: v0.0.2-1-g81c335d _src_path: {REPO_BUNDLE_PATH} author_name: Guybrush project_name: to become a pirate """ ) assert readme.read_text() == dedent( """ Let me introduce myself. My name is Guybrush. My project is to become a pirate. Thanks for your grog. """ ) commit("-m", "Update template to v0.0.2-1-g81c335d") assert not git("status", "--porcelain") # No more updates exist, so updating again should change nothing CopierApp.invoke(force=True, vcs_ref="HEAD") assert not git("status", "--porcelain") # If I change an option, it updates properly copy( data={"author_name": "Largo LaGrande", "project_name": "to steal a lot"}, force=True, vcs_ref="HEAD", ) assert readme.read_text() == dedent( """ Let me introduce myself. My name is Largo LaGrande. My project is to steal a lot. Thanks for your grog. """ ) commit("-m", "Subproject evolved") # Reapply template ignoring subproject evolution Worker( data={"author_name": "Largo LaGrande", "project_name": "to steal a lot"}, force=True, vcs_ref="HEAD", ).run_copy() assert readme.read_text() == dedent( """ Let me introduce myself. My name is Largo LaGrande. My project is to steal a lot. Thanks for your attention. """ )
def commit(self) -> OptStr: """If the template is VCS-tracked, get its commit description.""" if self.vcs == "git": with local.cwd(self.local_abspath): return git("describe", "--tags", "--always").strip()
def test_publish(capsys, configured, answer_prompts): github_merge_commit(111) responses.add( responses.GET, ISSUE_URL, json=PULL_REQUEST_JSON, status=200, content_type='application/json', ) responses.add( responses.GET, LABEL_URL, json=BUG_LABEL_JSON, status=200, content_type='application/json', ) responses.add( responses.POST, RELEASES_URL, json={'upload_url': 'foo'}, status=200, content_type='application/json', ) changes.initialise() stage.stage( draft=False, release_name='Icarus', release_description='The first flight' ) release_notes_path = Path( 'docs/releases/0.0.2-{}-Icarus.md'.format(date.today().isoformat()) ) assert release_notes_path.exists() publish.publish() pre = textwrap.dedent( """\ Staging [fix] release for version 0.0.2... Running: bumpversion --verbose --allow-dirty --no-commit --no-tag patch... Generating Release... Writing release notes to {release_notes_path}... Publishing release 0.0.2... Running: git add version.txt .bumpversion.cfg {release_notes_path}... Running: git commit --message="# 0.0.2 ({release_date}) Icarus """.format( release_notes_path=release_notes_path, release_date=date.today().isoformat() ) ).splitlines() expected_release_notes_content = [ 'The first flight', '## Bug', '* #111 The title of the pull request', ] post = textwrap.dedent( """\ "... Running: git tag 0.0.2... Running: git push --tags... Creating GitHub Release... Published release 0.0.2... """ ).splitlines() out, _ = capsys.readouterr() assert pre + expected_release_notes_content + post == out.splitlines() last_commit = git(shlex.split('show --name-only')) expected_files = ['version.txt', '.bumpversion.cfg', release_notes_path] assert [ expected_file for expected_file in expected_files if str(expected_file) in last_commit ] assert '0.0.2' in git(shlex.split('tag --list')) assert release_notes_path.exists() expected_release_notes = [ '# 0.0.2 ({}) Icarus'.format(date.today().isoformat()), 'The first flight', '## Bug', '* #111 The title of the pull request', ] assert expected_release_notes == release_notes_path.read_text().splitlines()
def git_repo(tmpdir): with CliRunner().isolated_filesystem() as repo_dir: for file_path, content in FILE_CONTENT.items(): open(file_path, 'w').write('\n'.join(content)) git('init') git(shlex.split('config --local user.email "*****@*****.**"')) git( shlex.split( 'remote add origin https://github.com/michaeljoseph/test_app.git' ) ) tmp_push_repo = Path(str(tmpdir)) git('init', '--bare', str(tmp_push_repo)) git( shlex.split( 'remote set-url --push origin {}'.format(tmp_push_repo.as_uri()) ) ) git('add', [file for file in FILE_CONTENT.keys()]) git('commit', '-m', 'Initial commit') git(shlex.split('tag 0.0.1')) yield repo_dir
def test_transtion_to_copier(tmp_path: Path, cloned_template: Path, any_odoo_version: float): """Test transition from old git-clone-based workflow to new copier-based.""" tag = "v999999.99.99" with local.cwd(cloned_template): git("tag", "--delete", "test") git("tag", "--force", tag) # Emulate user cloning scaffolding using the old workflow git("clone", "https://github.com/Tecnativa/doodba-scaffolding", tmp_path) with local.cwd(tmp_path): # Emulate user modifying some basic variables and committing env_file = tmp_path / ".env" env_contents = env_file.read_text() env_contents = env_contents.replace( "ODOO_MAJOR=11", f"ODOO_MAJOR={int(any_odoo_version)}") env_contents = env_contents.replace( "ODOO_MINOR=11.0", f"ODOO_MINOR={any_odoo_version:.1f}") env_contents = env_contents.replace( "ODOO_IMAGE=docker.io/myuser/myproject-odoo", f"ODOO_IMAGE=registry.example.com/custom-team/custom-project-odoo", ) env_file.write_text(env_contents) addons_file = tmp_path / "odoo" / "custom" / "src" / "addons.yaml" addons_file.write_text('server-tools: ["*"]') assert 'server-tools: ["*"]' in addons_file.read_text() answers_file = tmp_path / ".copier-answers.yml" answers_file_contents = answers_file.read_text() answers_file_contents = answers_file_contents.replace( "_src_path: https://github.com/Tecnativa/doodba-copier-template.git", f"_src_path: {cloned_template}", ) answers_file.write_text(answers_file_contents) assert f"_src_path: {cloned_template}" in answers_file.read_text() dep_files = glob( str(tmp_path / "odoo" / "custom" / "dependencies" / "*.txt")) assert len(dep_files) == 5 for dep_file in map(Path, dep_files): with dep_file.open("a") as dep_fd: dep_fd.write("\n# a comment") git("add", ".") git("commit", "-m", "update") # Emulate user upgrading to copier, passing the right variables copy( dst_path=str(tmp_path), force=True, data={ "odoo_version": any_odoo_version, "odoo_oci_image": "registry.example.com/custom-team/custom-project-odoo", }, vcs_ref=tag, ) env_contents = env_file.read_text() assert f"ODOO_MAJOR={int(any_odoo_version)}" in env_contents assert f"ODOO_MINOR={any_odoo_version:.1f}" in env_contents assert (tmp_path / ".copier-answers.yml").is_file() assert 'server-tools: ["*"]' in addons_file.read_text() for dep_file in map(Path, dep_files): assert dep_file.read_text().endswith("\n# a comment") # Check migrations ran fine assert not (tmp_path / ".travis.yml").exists() assert not (tmp_path / ".vscode" / "doodba").exists() assert not (tmp_path / ".vscode" / "doodbasetup.py").exists() assert not (tmp_path / "odoo" / "custom" / "src" / "private" / ".empty").exists() # Ensure migrations are resilient to subproject changes invoke( "--search-root", cloned_template, "--collection", "migrations", "from-doodba-scaffolding-to-copier", )
def clone_or_pull(repo_dict, to_dir): """ Clone or pull a repository and switch to the desired branch. If the directory already exists, we will try to du a pull with --rebase. In case anything goes wrong, we exit and print a simple diagnostic message. Args: url (str): Where is the remote repository? to_dir (str): Where should we clone/update to? branch (str): Which branch should we check out? Defaults to the repo's master. """ url = repo_dict["url"] branch = repo_dict.get("branch") commit_hash = repo_dict.get("commit_hash") from plumbum.cmd import git if not os.path.exists(os.path.join(to_dir, ".git/")): git_clone = git["clone", url, to_dir, "--recursive", "--depth=1"] if branch: git_clone = git_clone["--branch", branch] git_clone() elif not commit_hash: # If we haven't specified a commit hash, # fetch the latest version. with local.cwd(to_dir): git("remote", "update") locl = git("rev-parse", "@{0}") remote = git("rev-parse", "@{u}") base = git("merge-base", "@", "@{u}") if locl == remote: print("{:s} is up-to-date.".format(url)) elif locl == base: git("pull", "--rebase") git("submodule", "update") elif remote == base: print("push required") exit(1) else: print("{:s} has diverged from its remote.".format(to_dir)) exit(1) if commit_hash: with local.cwd(to_dir): # We only need to do something if we aren't already at the # latest commit hash current_hash = git("rev-parse", "--verify", "HEAD").rstrip("\n") if current_hash != commit_hash: # Make sure we have a full history, not just depth 1 print(( "HEAD for repository {:s} is not at configured commit hash {:s}, fetching and checking out.".format( url, commit_hash))) git("fetch", "--unshallow") git_checkout = git("checkout", commit_hash)
def test_overwrite_answers_file_always(tmp_path_factory, answers_file: Optional[RelativePath]): src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree({ "copier.yaml": "question_1: true", "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", "answer_1.jinja": "{{ question_1 }}", }) git("init") git("add", ".") git("commit", "-m1") git("tag", "1") build_file_tree({"copier.yaml": "question_1: false"}) git("commit", "-am2") git("tag", "2") # When copying, there's nothing to overwrite, overwrite=False shouldn't hang run_copy(str(src), str(dst), vcs_ref="1", defaults=True, answers_file=answers_file) with local.cwd(dst): git("init") git("add", ".") git("commit", "-m1") # When updating, the only thing to overwrite is the copier answers file, # which shouldn't ask, so also this shouldn't hang with overwrite=False run_update(defaults=True, answers_file=answers_file) answers = yaml.safe_load( Path(dst, answers_file or ".copier-answers.yml").read_bytes()) assert answers["question_1"] is True assert answers["_commit"] == "2" assert (dst / "answer_1").read_text() == "True"
def create_repo(self): with local.cwd(self.projectPath): log.info(cmd.git("init")) log.info(cmd.git("add", ".")) log.info(cmd.git("commit", "-m", "initial commit"))
def add_new_files(self): # fixme use GitPorcelainPorcelain with local.cwd(self.projectPath): log.info(cmd.git("add", "--all", "."))
def test_updatediff(tmp_path_factory): src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) # Prepare repo bundle repo = src / "repo" bundle = src / "demo_updatediff_repo.bundle" last_commit = "" build_file_tree({ repo / ".copier-answers.yml.jinja": """\ # Changes here will be overwritten by Copier {{ _copier_answers|to_nice_yaml }} """, repo / "copier.yml": """\ _envops: "keep_trailing_newline": True project_name: to become a pirate author_name: Guybrush """, repo / "README.txt.jinja": """ Let me introduce myself. My name is {{author_name}}, and my project is {{project_name}}. Thanks for your attention. """, }) with local.cwd(repo): git("init") git("add", ".") git("commit", "-m", "Guybrush wants to be a pirate") git("tag", "v0.0.1") build_file_tree({ repo / "copier.yml": """\ _envops: "keep_trailing_newline": True project_name: to become a pirate author_name: Guybrush _migrations: - version: v0.0.1 before: - touch before-v0.0.1 after: - touch after-v0.0.1 - version: v0.0.2 before: - touch before-v0.0.2 after: - touch after-v0.0.2 - version: v1.0.0 before: - touch before-v1.0.0 after: - touch after-v1.0.0 """, }) with local.cwd(repo): git("init") git("add", ".") git("commit", "-m", "Add migrations") git("tag", "v0.0.2") build_file_tree({ repo / "copier.yml": """\ _envops: "keep_trailing_newline": True project_name: to rule author_name: Elaine _migrations: - version: v0.0.1 before: - touch before-v0.0.1 after: - touch after-v0.0.1 - version: v0.0.2 before: - touch before-v0.0.2 after: - touch after-v0.0.2 - version: v1.0.0 before: - touch before-v1.0.0 after: - touch after-v1.0.0 """, repo / "README.txt.jinja": """ Let me introduce myself. My name is {{author_name}}. My project is {{project_name}}. Thanks for your attention. """, }) with local.cwd(repo): git("init") git("add", ".") git("commit", "-m", "Elaine wants to rule") git("bundle", "create", bundle, "--all") last_commit = git("describe", "--tags").strip() # Generate repo bundle target = dst / "target" readme = target / "README.txt" answers = target / ".copier-answers.yml" commit = git["commit", "--all"] # Run copier 1st time, with specific tag CopierApp.invoke( "copy", str(bundle), str(target), defaults=True, overwrite=True, vcs_ref="v0.0.1", ) # Check it's copied OK assert answers.read_text() == dedent(f"""\ # Changes here will be overwritten by Copier _commit: v0.0.1 _src_path: {bundle} author_name: Guybrush project_name: to become a pirate\n """) assert readme.read_text() == dedent(""" Let me introduce myself. My name is Guybrush, and my project is to become a pirate. Thanks for your attention. """) # Init destination as a new independent git repo with local.cwd(target): git("init") # Configure git in case you're running in CI git("config", "user.name", "Copier Test") git("config", "user.email", "test@copier") # Commit changes git("add", ".") commit("-m", "hello world") # Emulate the user modifying the README by hand with open(readme, "w") as readme_fd: readme_fd.write( dedent(""" Let me introduce myself. My name is Guybrush, and my project is to become a pirate. Thanks for your grog. """)) commit("-m", "I prefer grog") # Update target to latest tag and check it's updated in answers file CopierApp.invoke(defaults=True, overwrite=True) assert answers.read_text() == dedent(f"""\ # Changes here will be overwritten by Copier _commit: v0.0.2 _src_path: {bundle} author_name: Guybrush project_name: to become a pirate\n """) # Check migrations were executed properly assert not (target / "before-v0.0.1").is_file() assert not (target / "after-v0.0.1").is_file() assert (target / "before-v0.0.2").is_file() assert (target / "after-v0.0.2").is_file() (target / "before-v0.0.2").unlink() (target / "after-v0.0.2").unlink() assert not (target / "before-v1.0.0").is_file() assert not (target / "after-v1.0.0").is_file() commit("-m", "Update template to v0.0.2") # Update target to latest commit, which is still untagged CopierApp.invoke(defaults=True, overwrite=True, vcs_ref="HEAD") # Check no new migrations were executed assert not (target / "before-v0.0.1").is_file() assert not (target / "after-v0.0.1").is_file() assert not (target / "before-v0.0.2").is_file() assert not (target / "after-v0.0.2").is_file() assert not (target / "before-v1.0.0").is_file() assert not (target / "after-v1.0.0").is_file() # Check it's updated OK assert answers.read_text() == dedent(f"""\ # Changes here will be overwritten by Copier _commit: {last_commit} _src_path: {bundle} author_name: Guybrush project_name: to become a pirate\n """) assert readme.read_text() == dedent(""" Let me introduce myself. My name is Guybrush. My project is to become a pirate. Thanks for your grog. """) commit("-m", f"Update template to {last_commit}") assert not git("status", "--porcelain") # No more updates exist, so updating again should change nothing CopierApp.invoke(defaults=True, overwrite=True, vcs_ref="HEAD") assert not git("status", "--porcelain") # If I change an option, it updates properly copy( data={ "author_name": "Largo LaGrande", "project_name": "to steal a lot" }, defaults=True, overwrite=True, vcs_ref="HEAD", ) assert readme.read_text() == dedent(""" Let me introduce myself. My name is Largo LaGrande. My project is to steal a lot. Thanks for your grog. """) commit("-m", "Subproject evolved") # Reapply template ignoring subproject evolution Worker( data={ "author_name": "Largo LaGrande", "project_name": "to steal a lot" }, defaults=True, overwrite=True, vcs_ref="HEAD", ).run_copy() assert readme.read_text() == dedent(""" Let me introduce myself. My name is Largo LaGrande. My project is to steal a lot. Thanks for your attention. """)
def test_v2_7_0_migration( tmp_path: Path, cloned_template: Path, supported_odoo_version: float, ): """Test migration to v2.1.1.""" pre, target = "v2.6.1", "v2.7.0" # This part makes sense only when target version is not yet released with local.cwd(cloned_template): if target not in git("tag").split(): git("tag", "-d", "test") git("tag", target) with local.cwd(tmp_path): # Copy previous version copy( src_path=str(cloned_template), vcs_ref=pre, force=True, answers_file=".custom.copier-answers.yaml", data={ "odoo_version": supported_odoo_version, }, ) git("config", "commit.gpgsign", "false") git("add", ".") git("commit", "-am", "reformat", retcode=1) git("commit", "-am", f"copied from template in {pre}") # Update to target version copy(answers_file=".custom.copier-answers.yaml", vcs_ref=target, force=True) git("add", ".") git("commit", "-am", "reformat", retcode=1) git("commit", "-am", f"updated from template in {target}") # Assert config files removal assert not Path(".vscode", "settings.json").exists()
def test_skip_update(tmp_path_factory): src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree({ "copier.yaml": "_skip_if_exists: [skip_me]", "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", "skip_me": "1", }) git("init") git("add", ".") git("commit", "-m1") git("tag", "1.0.0") run_copy(str(src), dst, defaults=True, overwrite=True) skip_me: Path = dst / "skip_me" answers_file = dst / ".copier-answers.yml" answers = yaml.safe_load(answers_file.read_text()) assert skip_me.read_text() == "1" assert answers["_commit"] == "1.0.0" skip_me.write_text("2") with local.cwd(dst): git("init") git("add", ".") git("commit", "-m1") with local.cwd(src): build_file_tree({"skip_me": "3"}) git("commit", "-am2") git("tag", "2.0.0") run_update(dst, defaults=True, overwrite=True) answers = yaml.safe_load(answers_file.read_text()) assert skip_me.read_text() == "2" assert answers["_commit"] == "2.0.0" assert not (dst / "skip_me.rej").exists()
def test_stage_discard(capsys, configured): responses.add( responses.GET, LABEL_URL, json=BUG_LABEL_JSON, status=200, content_type='application/json', ) github_merge_commit(111) responses.add( responses.GET, ISSUE_URL, json=PULL_REQUEST_JSON, status=200, content_type='application/json', ) changes.initialise() stage.stage( draft=False, release_name='Icarus', release_description='The first flight' ) release_notes_path = Path( 'docs/releases/0.0.2-{}-Icarus.md'.format(date.today().isoformat()) ) assert release_notes_path.exists() result = git(shlex.split('-c color.status=false status --short --branch')) modified_files = [ '## master', ' M .bumpversion.cfg', # ' M CHANGELOG.md', ' M version.txt', '?? docs/', '', ] assert '\n'.join(modified_files) == result stage.discard(release_name='Icarus', release_description='The first flight') expected_output = textwrap.dedent( """\ Staging [fix] release for version 0.0.2... Running: bumpversion --verbose --allow-dirty --no-commit --no-tag patch... Generating Release... Writing release notes to {release_notes_path}... Discarding currently staged release 0.0.2... Running: git checkout -- version.txt .bumpversion.cfg... Running: rm {release_notes_path}... """.format( release_notes_path=release_notes_path ) ) out, _ = capsys.readouterr() assert expected_output == out result = git(shlex.split('-c color.status=false status --short --branch')) modified_files = ['## master', ''] assert '\n'.join(modified_files) == result