Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/workflow_users/workflow_deployment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ Further, the workflow definition Snakefile can be arbitrarily extended and modif

It is highly advisable to put the deployed workflow into a new (perhaps private) git repository (e.g., see `here <https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line>`_ for instructions how to do that with Github).

If you want to pin the deployment to an exact commit (e.g. for full reproducibility independent of any future changes to a branch or tag), use ``--commit`` instead of ``--tag``/``--branch``:

.. code-block:: console

$ snakedeploy deploy-workflow https://github.com/snakemake-workflows/dna-seq-varlociraptor /tmp/dest --commit 87709354b54391aee5dbb01a64cacfc20aed5ec3

This will generate a module declaration pinned to that exact commit:

.. code-block:: python

module dna_seq_varlociraptor:
snakefile:
github("snakemake-workflows/dna-seq-varlociraptor", path="workflow/Snakefile", commit="87709354b54391aee5dbb01a64cacfc20aed5ec3")
config:
config

Note that ``--commit``, ``--tag``, and ``--branch`` are mutually exclusive: exactly one of them has to be specified.

For more options and details, run

.. code-block:: console
Expand Down
14 changes: 10 additions & 4 deletions snakedeploy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,23 @@ def get_parser():
help="Path to create the deploying workflow in.",
)

deploy_workflow_parser.add_argument(
ref_group = deploy_workflow_parser.add_mutually_exclusive_group(required=True)

ref_group.add_argument(
"--tag",
help="Git tag to deploy from (e.g. a certain release).",
)

deploy_workflow_parser.add_argument(
ref_group.add_argument(
"--branch",
help="Git branch to deploy from.",
)

ref_group.add_argument(
"--commit",
help="Git commit (SHA) to deploy from and pin the resulting module to.",
)

deploy_group.add_argument(
"--name",
help="The name for the module in the resulting Snakefile (default: repository name).",
Expand Down Expand Up @@ -290,13 +297,12 @@ def help(return_code=0):

try:
if args.subcommand == "deploy-workflow":
if not (args.tag or args.branch):
raise UserError("Please specify either --tag or --branch")
deploy(
args.repo,
name=args.name,
tag=args.tag,
branch=args.branch,
commit=args.commit,
dest_path=Path(args.dest),
force=args.force,
)
Expand Down
30 changes: 27 additions & 3 deletions snakedeploy/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(
dest: Path,
tag: str | None = None,
branch: str | None = None,
commit: str | None = None,
force=False,
):
self.provider = get_provider(source)
Expand All @@ -28,6 +29,7 @@ def __init__(
self._cloned = None
self.tag = tag
self.branch = branch
self.commit = commit

def __enter__(self):
return self
Expand Down Expand Up @@ -137,7 +139,9 @@ def repo_clone(self):
logger.info("Obtaining source repository...")
self._cloned = tempfile.TemporaryDirectory()
self.provider.clone(self._cloned.name)
if self.tag is not None:
if self.commit is not None:
self.provider.checkout(self._cloned.name, self.commit)
elif self.tag is not None:
self.provider.checkout(self._cloned.name, self.tag)
elif self.branch is not None:
self.provider.checkout(self._cloned.name, self.branch)
Expand Down Expand Up @@ -225,7 +229,7 @@ def deploy_snakefile(self, tmpdir: str, name: str):
module_deployment = template.render(
name=name,
snakefile=self.provider.get_source_file_declaration(
snakefile, self.tag, self.branch
snakefile, self.tag, self.branch, self.commit
),
repo=self.provider.source_url,
config=config,
Expand All @@ -250,6 +254,7 @@ def deploy(
tag: str | None,
branch: str | None,
dest_path: Path,
commit: str | None = None,
force=False,
):
"""
Expand All @@ -271,8 +276,27 @@ def deploy(
force=True
)

Instead of a tag or branch, a specific commit can be pinned (the three
are mutually exclusive):

.. code-block:: python

from snakedeploy.deploy import deploy
deploy(
"https://github.com/snakemake-workflows/dna-seq-varlociraptor",
dest_path="/tmp/dest",
name="dna_seq",
commit="a1b2c3d4e5f6...",
force=True
)

"""
with WorkflowDeployer(
source=source_url, dest=dest_path, tag=tag, branch=branch, force=force
source=source_url,
dest=dest_path,
tag=tag,
branch=branch,
commit=commit,
force=force,
) as sd:
sd.deploy(name=name)
21 changes: 16 additions & 5 deletions snakedeploy/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ def get_raw_file(self, path: str, tag: str):
)
return f"{self.source_url}/{path}"

def get_source_file_declaration(self, path: str, tag: str, branch: str):
def get_source_file_declaration(
self, path: str, tag: str, branch: str, commit: str | None = None
):
relative_path = path.replace(self.source_url, "").strip(os.sep)
Comment on lines +74 to 77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not silently ignore --commit for local repositories.

repo_clone invokes provider.checkout(..., commit), but Local.checkout() is a no-op and this declaration cannot encode the commit. A local deployment therefore copies the current working tree rather than the requested snapshot. Either implement commit checkout for Git-backed local sources or reject --commit for the Local provider.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@snakedeploy/providers.py` around lines 77 - 80, Ensure the Local provider
does not silently ignore a requested commit: either implement commit-aware
checkout in Local.checkout or explicitly reject --commit for Local before
deployment proceeds. Update the related get_source_file_declaration flow only as
needed to preserve the requested snapshot behavior.

return f'"{relative_path}"'

Expand Down Expand Up @@ -103,11 +105,20 @@ def checkout(self, path: str, ref: str):
def get_raw_file(self, path: str, tag: str):
return f"{self.source_url}/raw/{tag}/{path}"

def get_source_file_declaration(self, path: str, tag: str, branch: str):
def get_source_file_declaration(
self, path: str, tag: str, branch: str, commit: str | None = None
):
owner_repo = "/".join(self.source_url.split("/")[-2:])
if not (tag or branch):
raise UserError("Either tag or branch has to be specified for deployment.")
ref_arg = f'tag="{tag}"' if tag is not None else f'branch="{branch}"'
if not (tag or branch or commit):
raise UserError(
"Either tag, branch, or commit has to be specified for deployment."
)
if commit is not None:
ref_arg = f'commit="{commit}"'
elif tag is not None:
ref_arg = f'tag="{tag}"'
else:
ref_arg = f'branch="{branch}"'
return f'{self.name}("{owner_repo}", path="{path}", {ref_arg})'


Expand Down
9 changes: 9 additions & 0 deletions tests/test_client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ dest=$tmpdir/gitlab-testing
repo="https://gitlab.com/nate-d-olson/snaketestworkflow"
runTest 0 $output snakedeploy deploy-workflow "${repo}" "${dest}" --name snake-test --branch master

echo
echo "#### Testing snakedeploy deployment pinned to a specific commit"
dest=$tmpdir/commit-testing
repo="https://github.com/snakemake-workflows/dna-seq-varlociraptor"
commit_sha="87709354b54391aee5dbb01a64cacfc20aed5ec3"
runTest 0 $output snakedeploy deploy-workflow "${repo}" "${dest}" --commit ${commit_sha} --name dna-seq-commit
runTest 0 $output grep "commit=\"${commit_sha}\"" ${dest}/workflow/Snakefile
runTest 2 $output snakedeploy deploy-workflow "${repo}" "${dest}" --branch master --commit ${commit_sha}

echo
echo "#### Testing snakedeploy local deployment"
local=$tmpdir/rna-seq-star-deseq2
Expand Down
Loading