diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eef34f0c0..635ecdde6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,7 @@ Release 0.11.0 (unreleased) * Support multiple licenses per project (#788) * Add evidence to sbom report (#788) * Let action work outside of dfetch repo (#816) +* Handle SVN tags with special characters (#811) Release 0.10.0 (released 2025-03-12) ==================================== diff --git a/dfetch/project/svn.py b/dfetch/project/svn.py index be3de3c3e..d81cfb5d9 100644 --- a/dfetch/project/svn.py +++ b/dfetch/project/svn.py @@ -3,6 +3,7 @@ import os import pathlib import re +import urllib.parse from typing import Dict, List, NamedTuple, Optional, Tuple from dfetch.log import get_logger @@ -204,6 +205,8 @@ def _determine_what_to_fetch(self, version: Version) -> Tuple[str, str, str]: else self.DEFAULT_BRANCH ) + branch_path = urllib.parse.quote(branch_path) + revision = version.revision or self._get_revision(branch_path) if not revision.isdigit(): diff --git a/features/fetch-svn-repo.feature b/features/fetch-svn-repo.feature index 9703fa670..f547b56d7 100644 --- a/features/fetch-svn-repo.feature +++ b/features/fetch-svn-repo.feature @@ -74,3 +74,32 @@ Feature: Fetching dependencies from a svn repository SomeFile.txt dfetch.yaml """ + + Scenario: SVN repository with a tags can be fetched + Given the manifest 'dfetch.yaml' in MyProject + """ + manifest: + version: 0.0 + projects: + - name: SomeProject + url: some-remote-server/SomeProject + tag: 'v1.2.3' + + - name: SomeOtherProject + url: some-remote-server/SomeOtherProject + tag: 'v 1&;{6}' + """ + And a svn-server "SomeProject" with the tag "v1.2.3" + And a svn-server "SomeOtherProject" with the tag "v 1&;{6}" + When I run "dfetch update" + Then 'MyProject' looks like: + """ + MyProject/ + SomeOtherProject/ + .dfetch_data.yaml + README.md + SomeProject/ + .dfetch_data.yaml + README.md + dfetch.yaml + """ diff --git a/features/steps/svn_steps.py b/features/steps/svn_steps.py index c2c5bb7af..e529a7218 100644 --- a/features/steps/svn_steps.py +++ b/features/steps/svn_steps.py @@ -21,10 +21,10 @@ def create_svn_server_and_repo(context, name="svn-server"): repo_path = name pathlib.Path(server_path).mkdir(parents=True, exist_ok=True) - subprocess.call(["svnadmin", "create", "--fs-type", "fsfs", server_path]) + subprocess.check_call(["svnadmin", "create", "--fs-type", "fsfs", server_path]) current_path = "/".join(os.getcwd().split(os.path.sep) + [server_path]) - subprocess.call(["svn", "checkout", f"file:///{current_path}", repo_path]) + subprocess.check_call(["svn", "checkout", f"file:///{current_path}", repo_path]) return repo_path @@ -36,12 +36,18 @@ def create_stdlayout(): def add_and_commit(msg): - subprocess.call(["svn", "add", "--force", "."]) - subprocess.call(["svn", "ci", "-m", f'"{msg}"']) + subprocess.check_call(["svn", "add", "--force", "."]) + subprocess.check_call(["svn", "ci", "-m", f'"{msg}"']) def commit_all(msg): - subprocess.call(["svn", "commit", "--depth", "empty", ".", "-m", f'"{msg}"']) + subprocess.check_call(["svn", "commit", "--depth", "empty", ".", "-m", f'"{msg}"']) + + +def create_tag(tag_name): + """Create a tag from trunk.""" + subprocess.check_call(["svn", "copy", "trunk", f"tags/{tag_name}"]) + subprocess.check_call(["svn", "ci", "-m", f'"Created tag {tag_name}"']) def add_externals(externals): @@ -51,9 +57,10 @@ def add_externals(externals): revision = f"@{external['revision']}" if external["revision"] else "" external_list.write(f"{external['url']}{revision} {external['path']}\n") - subprocess.call(["svn", "propset", "svn:externals", "-F", external_list.name, "."]) + subprocess.check_call( + ["svn", "propset", "svn:externals", "-F", external_list.name, "."] + ) commit_all("Added externals") - subprocess.call(["svn", "update"]) @given("a svn repo with the following externals") @@ -65,7 +72,8 @@ def step_impl(context): @given('a svn-server "{name}"') @given('a svn-server "{name}" with the files') -def step_impl(context, name): +@given('a svn-server "{name}" with the tag "{tag_name}"') +def step_impl(context, name, tag_name=None): repo_path = create_svn_server_and_repo(context, name) files = context.table or [{"path": "README.md"}] @@ -76,6 +84,8 @@ def step_impl(context, name): for file in files: generate_file(file["path"], "some content") add_and_commit("Added files") + if tag_name: + create_tag(tag_name) @given('a non-standard svn-server "{name}" with the files')