Skip to content

Commit

Permalink
Merge pull request #515 from ACCESS-NRI/503-support-cloning-from-comm…
Browse files Browse the repository at this point in the history
…it-hash

Add support for cloning configuration using a commit hash
  • Loading branch information
jo-basevi authored Sep 24, 2024
2 parents eb8e8f8 + 8c9dcaa commit 6ee85bb
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 11 deletions.
11 changes: 8 additions & 3 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,21 @@ For example::
Where ``${REPOSITORY}`` is the git URL or path of the repository to clone from,
for example, https://github.com/payu-org/mom-example.git.

To clone and checkout an existing git branch, use the ``--branch`` flag and
To clone and checkout an existing git branch, use the ``-B/--branch`` flag and
specify the branch name::

payu clone --branch ${EXISTING_BRANCH} ${REPOSITORY} my_expt

To create and checkout a new git branch use ``--new-branch`` and specify a
new branch name:
To create and checkout a new git branch use ``-b/--new-branch`` and specify a
new branch name::

payu clone --new-branch ${NEW_BRANCH} ${REPOSITORY} my_expt

To create a new git branch starting from a tag or commit, use ``-s/--start-point``
flag::

payu clone -b ${NEW_BRANCH} -s {COMMIT_HASH|TAG} ${REPOSITORY} my_expt

To see more configuration options for ``payu clone``,
run::

Expand Down
16 changes: 11 additions & 5 deletions payu/branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def switch_symlink(lab_dir_path: Path, control_path: Path,
def clone(repository: str,
directory: Path,
branch: Optional[str] = None,
start_point: Optional[str] = None,
new_branch_name: Optional[str] = None,
keep_uuid: bool = False,
model_type: Optional[str] = None,
Expand All @@ -227,11 +228,11 @@ def clone(repository: str,
directory: Path
The control directory where the repository will be cloned
branch: Optional[str]
Name of branch to clone and checkout
Name of branch to checkout during the git clone
start_point: Optional[str]
Branch-name/commit/tag to start new branch from
new_branch_name: Optional[str]
Name of new branch to create and checkout.
If branch is also defined, the new branch will start from the
latest commit of the branch.
Name of new branch to create and checkout
keep_uuid: bool, default False
Keep UUID unchanged, if it exists
config_path: Optional[Path]
Expand All @@ -248,6 +249,10 @@ def clone(repository: str,
Parent experiment UUID to add to generated metadata
Returns: None
Note: branch, if defined, can be set to avoid initially checking out the
default branch during git clone - this is useful for repositories where
the default branch is not a payu configuration.
"""
# Resolve directory to an absolute path
control_path = directory.resolve()
Expand Down Expand Up @@ -278,7 +283,8 @@ def clone(repository: str,
control_path=control_path,
model_type=model_type,
lab_path=lab_path,
parent_experiment=parent_experiment)
parent_experiment=parent_experiment,
start_point=start_point)
else:
# Checkout branch
if branch is None:
Expand Down
11 changes: 11 additions & 0 deletions payu/subcommands/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@
}
}

# Clone branch
clone_start_point = {
'flags': ('--start-point', '-s'),
'parameters': {
'action': 'store',
'dest': 'start_point',
'default': None,
'help': 'New branch will start from this commit or tag'
}
}

# Clone create branch
new_branch_name = {
'flags': ('--new-branch', '-b'),
Expand Down
7 changes: 4 additions & 3 deletions payu/subcommands/clone_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
args.keep_uuid, args.clone_branch,
args.repository, args.local_directory,
args.new_branch_name, args.restart_path,
args.parent_experiment]
args.parent_experiment, args.clone_start_point]


def transform_strings_to_path(path_str=None):
Expand All @@ -27,7 +27,7 @@ def transform_strings_to_path(path_str=None):

def runcmd(model_type, config_path, lab_path, keep_uuid,
branch, repository, local_directory, new_branch_name, restart_path,
parent_experiment):
parent_experiment, start_point):
"""Execute the command."""
config_path = transform_strings_to_path(config_path)
restart_path = transform_strings_to_path(restart_path)
Expand All @@ -43,7 +43,8 @@ def runcmd(model_type, config_path, lab_path, keep_uuid,
lab_path=lab_path,
new_branch_name=new_branch_name,
restart_path=restart_path,
parent_experiment=parent_experiment)
parent_experiment=parent_experiment,
start_point=start_point)


runscript = runcmd
47 changes: 47 additions & 0 deletions test/test_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,53 @@ def test_clone(mock_uuid):
assert [head.name for head in cloned_repo2.heads] == ["Branch1", "Branch2"]


@pytest.mark.parametrize(
"start_point_type", ["commit", "tag"]
)
def test_clone_startpoint(start_point_type):
# Create a repo to clone
source_repo_path = tmpdir / "sourceRepo"
source_repo_path.mkdir()
source_repo = setup_control_repository(path=source_repo_path)

# Create branch1
branch1 = source_repo.create_head("Branch1")
branch1_commit = branch1.object.hexsha
if start_point_type == "tag":
source_repo.create_tag('v1.0', ref=branch1.commit)
start_point = 'v1.0'
elif start_point_type == "commit":
start_point = branch1_commit

# Add another commit on main branch so the commit is different to branch1
(source_repo_path / "mock_file.txt").touch()
source_repo.index.add("mock_file.txt")
source_repo.index.commit("Another commit with a mock file")

source_repo_commit = source_repo.active_branch.object.hexsha
assert source_repo_commit != branch1_commit

# Run Clone
cloned_repo_path = tmpdir / "clonedRepo"
with cd(tmpdir):
clone(
repository=str(source_repo_path),
directory=cloned_repo_path,
lab_path=labdir,
new_branch_name="Branch3",
start_point=start_point
)

cloned_repo = git.Repo(cloned_repo_path)

# Check branched starting from start point
second_latest_commit = list(cloned_repo.iter_commits(max_count=2))[1]
assert second_latest_commit.hexsha == branch1_commit

# Latest commit is different (new commit from metadata)
assert source_repo_commit != cloned_repo.active_branch.object.hexsha


def add_and_commit_metadata(repo, metadata):
"""Helper function to create/update metadata file and commit"""
metadata_path = ctrldir / "metadata.yaml"
Expand Down

0 comments on commit 6ee85bb

Please sign in to comment.