Skip to content
Open
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
Expand Down
211 changes: 117 additions & 94 deletions test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Fixtures and utilities for testing vcs2l."""

import os
import re
import shutil
import subprocess
import tarfile
Expand All @@ -12,120 +13,142 @@

import yaml

REPO_LINK = 'https://github.com/ros-infrastructure/vcs2l.git'


def to_file_url(path):
return Path(path).as_uri()


def extract_commit(url):
"""Extract commit hash from version for zip/tar clients."""
m = re.search(r'vcs2l-([a-fA-F0-9]{40})', url)
return m.group(1) if m else None


def setup_git_repository(temp_dir):
"""Create a git repository for testing."""
repo_root = os.path.dirname(os.path.dirname(__file__))
gitrepo_path = os.path.join(temp_dir.name, 'gitrepo')

commits_count = int(
subprocess.check_output(
['git', 'rev-list', '--count', 'HEAD'], cwd=repo_root
).strip()
)

if commits_count == 1:
repo_root = REPO_LINK # codecov sparsely clones the repo

subprocess.check_call(['git', 'clone', repo_root, gitrepo_path])
try:
subprocess.check_call(['git', 'checkout', 'main'], cwd=gitrepo_path)
except subprocess.CalledProcessError:
# Create branch named 'main' as CI checks out with no branch
subprocess.check_call(['git', 'checkout', '-b', 'main'], cwd=gitrepo_path)

return gitrepo_path


def setup_tar_archive(temp_dir, target_commit):
"""Create a tar archive for testing by checking out the target commit."""
gitrepo_path = os.path.join(temp_dir.name, 'gitrepo')
tar_path = os.path.join(temp_dir.name, 'tar')

subprocess.check_call(['git', 'clone', gitrepo_path, tar_path])
subprocess.check_call(['git', 'checkout', target_commit], cwd=tar_path)
shutil.rmtree(os.path.join(tar_path, '.git')) # .git not present in tar archive

archive_dir = os.path.join(temp_dir.name, 'archive')
os.makedirs(archive_dir, exist_ok=True)
tarball_path = os.path.join(archive_dir, f'{target_commit}.tar.gz')

with tarfile.TarFile.open(tarball_path, 'w:gz') as tar:
tar.add(tar_path, arcname=f'vcs2l-{target_commit}')

return tarball_path


def setup_zip_archive(temp_dir, target_commit):
"""Create a zip archive for testing by checking out the target commit."""
gitrepo_path = os.path.join(temp_dir.name, 'gitrepo')
zip_path = os.path.join(temp_dir.name, 'zip')

subprocess.check_call(['git', 'clone', gitrepo_path, zip_path])
subprocess.check_call(['git', 'checkout', target_commit], cwd=zip_path)
shutil.rmtree(os.path.join(zip_path, '.git')) # .git not present in zip archive

archive_dir = os.path.join(temp_dir.name, 'archive')
os.makedirs(archive_dir, exist_ok=True)
zipfile_path = os.path.join(archive_dir, f'{target_commit}.zip')

with zipfile.ZipFile(zipfile_path, 'w') as zipf:
for root, dirs, files in os.walk(zip_path):
# Add directory entries
for dir_name in dirs:
dir_path = os.path.join(root, dir_name)
arcname = (
os.path.join(
f'vcs2l-{target_commit}', os.path.relpath(dir_path, zip_path)
)
+ '/'
)
zipf.write(dir_path, arcname)

# Add files
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.join(
f'vcs2l-{target_commit}', os.path.relpath(file_path, zip_path)
)
zipf.write(file_path, arcname)

return zipfile_path


class StagedReposFile(unittest.TestCase):
"""Fixture for testing git, tar, and zip clients."""

_git = which('git')
_git_env = {
**os.environ,
'GIT_AUTHOR_NAME': 'vcs2l',
'GIT_AUTHOR_DATE': '2005-01-01T00:00:00-06:00',
'GIT_AUTHOR_EMAIL': '[email protected]',
'GIT_COMMITTER_NAME': 'vcs2l',
'GIT_COMMITTER_DATE': '2005-01-01T00:00:00-06:00',
'GIT_COMMITTER_EMAIL': '[email protected]',
'GIT_CONFIG_GLOBAL': os.path.join(os.path.dirname(__file__), '.gitconfig'),
'LANG': 'en_US.UTF-8',
}
_commit_date = '2005-01-01T00:00:00'

temp_dir = None
repos_file_path = None

@classmethod
def setUpClass(cls):
def setUpClass(cls, repos_file=None):
if not cls._git:
raise unittest.SkipTest('`git` was not found')

cls.temp_dir = TemporaryDirectory(suffix='.vcstmp')

# Create the staged git repository
gitrepo_path = os.path.join(cls.temp_dir.name, 'gitrepo')
os.mkdir(gitrepo_path)
shutil.copy(
os.path.join(os.path.dirname(os.path.dirname(__file__)), 'LICENSE'),
gitrepo_path,
)
for command in (
('init', '--quiet', '.'),
('commit', '--quiet', '--allow-empty', '-m', '0.1.26'),
('tag', '0.1.26'),
('checkout', '--quiet', '-b', 'license'),
('add', 'LICENSE'),
('commit', '--quiet', '-m', 'Add LICENSE'),
('checkout', '--quiet', 'main'),
('merge', '--no-ff', '--quiet', 'license', '-m', "Merge branch 'license'"),
('branch', '--quiet', '-D', 'license'),
('commit', '--quiet', '--allow-empty', '-m', 'update changelog'),
('commit', '--quiet', '--allow-empty', '-m', '0.1.27'),
('tag', '0.1.27'),
('commit', '--quiet', '--allow-empty', '-m', "codin' codin' codin'"),
):
subprocess.check_call(
[
cls._git,
*command,
],
cwd=gitrepo_path,
env=cls._git_env,
)
if repos_file is None:
raise ValueError('A repos file must be provided')

# Create the archive stage
archive_path = os.path.join(cls.temp_dir.name, 'archive_dir')
os.mkdir(archive_path)
with open(os.path.join(archive_path, 'file_name.txt'), 'wb') as f:
f.write(b'Lorem Ipsum\n')

# Create a tar file
tarball_path = os.path.join(cls.temp_dir.name, 'archive.tar.gz')
with tarfile.TarFile.open(tarball_path, 'w:gz') as f:
f.add(archive_path, 'archive_dir')

# Create a zip file
zip_path = os.path.join(cls.temp_dir.name, 'archive.zip')
with zipfile.ZipFile(zip_path, mode='w') as f:
f.write(
os.path.join(archive_path, 'file_name.txt'),
os.path.join('archive_dir', 'file_name.txt'),
)
with open(repos_file, 'r', encoding='utf-8') as f:
repos_data = yaml.safe_load(f)

# Populate the staged.repos file
repos = {
'immutable/hash': {
'type': 'git',
'url': to_file_url(gitrepo_path),
'version': '5b3504594f7354121cf024dc734bf79e270cffd3',
},
'immutable/hash_tar': {
'type': 'tar',
'url': to_file_url(tarball_path),
'version': 'archive_dir',
},
'immutable/hash_zip': {
'type': 'zip',
'url': to_file_url(zip_path),
'version': 'archive_dir',
},
'immutable/tag': {
'type': 'git',
'url': to_file_url(gitrepo_path),
'version': 'tags/0.1.27',
},
'vcs2l': {
'type': 'git',
'url': to_file_url(gitrepo_path),
'version': 'heads/main',
},
'without_version': {
'type': 'git',
'url': to_file_url(gitrepo_path),
},
}
repos = repos_data.get('repositories')

# Create the temp git repository
gitrepo_path = setup_git_repository(cls.temp_dir)

# Use the existing file as a baseline
repos = repos_data['repositories'].copy()

for repo_name, repo_config in repos.items():
if repo_config['type'] == 'git':
repos[repo_name]['url'] = to_file_url(gitrepo_path)

elif repo_config['type'] == 'tar':
extracted_commit = extract_commit(repo_config['version'])
repos[repo_name]['url'] = to_file_url(
setup_tar_archive(cls.temp_dir, extracted_commit)
)

elif repo_config['type'] == 'zip':
extracted_commit = extract_commit(repo_config['version'])
repos[repo_name]['url'] = to_file_url(
setup_zip_archive(cls.temp_dir, extracted_commit)
)

cls.repos_file_path = os.path.join(cls.temp_dir.name, 'staged.repos')
with open(cls.repos_file_path, 'wb') as f:
Expand Down
2 changes: 1 addition & 1 deletion test/branch.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
....
=== ./immutable/hash (git) ===
(HEAD detached at 5b35045)
(HEAD detached at 377d5b3)
=== ./immutable/tag (git) ===
(HEAD detached at 0.1.27)
=== ./vcs2l (git) ===
Expand Down
4 changes: 2 additions & 2 deletions test/export_exact.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ repositories:
hash:
type: git
url: file:///vcstmp/gitrepo
version: 5b3504594f7354121cf024dc734bf79e270cffd3
version: 377d5b3d03c212f015cc832fdb368f4534d0d583
tag:
type: git
url: file:///vcstmp/gitrepo
version: 8087b72504968800cdf54759b11e0b753ec90736
version: bf9ca56de693a02b93ed423bcef589259d75eb0f
2 changes: 1 addition & 1 deletion test/export_exact_with_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ repositories:
hash:
type: git
url: file:///vcstmp/gitrepo
version: 5b3504594f7354121cf024dc734bf79e270cffd3
version: 377d5b3d03c212f015cc832fdb368f4534d0d583
tag:
type: git
url: file:///vcstmp/gitrepo
Expand Down
10 changes: 5 additions & 5 deletions test/import.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
......
=== ./immutable/hash (git) ===
Cloning into '.'...
Note: switching to '5b3504594f7354121cf024dc734bf79e270cffd3'.
Note: switching to '377d5b3d03c212f015cc832fdb368f4534d0d583'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
Expand All @@ -18,11 +18,11 @@ Or undo this operation with:

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 5b35045... update changelog
HEAD is now at 377d5b3... update changelog
=== ./immutable/hash_tar (tar) ===
Downloaded tarball from 'file:///vcstmp/archive.tar.gz' and unpacked it
Downloaded tarball from 'file:///vcstmp/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.tar.gz' and unpacked it
=== ./immutable/hash_zip (zip) ===
Downloaded zipfile from 'file:///vcstmp/archive.zip' and unpacked it
Downloaded zipfile from 'file:///vcstmp/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.zip' and unpacked it
=== ./immutable/tag (git) ===
Cloning into '.'...
Note: switching to 'tags/0.1.27'.
Expand All @@ -42,7 +42,7 @@ Or undo this operation with:

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 8087b72... 0.1.27
HEAD is now at bf9ca56... 0.1.27
=== ./vcs2l (git) ===
Cloning into '.'...
=== ./without_version (git) ===
Expand Down
12 changes: 6 additions & 6 deletions test/import_shallow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
Initialized empty Git repository in ./immutable/hash/.git/

From file:///vcstmp/gitrepo
* branch 5b3504594f7354121cf024dc734bf79e270cffd3 -> FETCH_HEAD
Note: switching to '5b3504594f7354121cf024dc734bf79e270cffd3'.
* branch 377d5b3d03c212f015cc832fdb368f4534d0d583 -> FETCH_HEAD
Note: switching to '377d5b3d03c212f015cc832fdb368f4534d0d583'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
Expand All @@ -21,11 +21,11 @@ Or undo this operation with:

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 5b35045... update changelog
HEAD is now at 377d5b3... update changelog
=== ./immutable/hash_tar (tar) ===
Downloaded tarball from 'file:///vcstmp/archive.tar.gz' and unpacked it
Downloaded tarball from 'file:///vcstmp/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.tar.gz' and unpacked it
=== ./immutable/hash_zip (zip) ===
Downloaded zipfile from 'file:///vcstmp/archive.zip' and unpacked it
Downloaded zipfile from 'file:///vcstmp/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.zip' and unpacked it
=== ./immutable/tag (git) ===
Initialized empty Git repository in ./immutable/tag/.git/

Expand All @@ -48,7 +48,7 @@ Or undo this operation with:

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 8087b72... 0.1.27
HEAD is now at bf9ca56... 0.1.27
=== ./vcs2l (git) ===
Cloning into '.'...
=== ./without_version (git) ===
Expand Down
25 changes: 25 additions & 0 deletions test/list_repos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
repositories:
immutable/hash:
type: git
url: https://github.com/ros-infrastructure/vcs2l.git
version: 377d5b3d03c212f015cc832fdb368f4534d0d583
immutable/hash_tar:
type: tar
url: https://github.com/ros-infrastructure/vcs2l/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.tar.gz
version: vcs2l-377d5b3d03c212f015cc832fdb368f4534d0d583
immutable/hash_zip:
type: zip
url: https://github.com/ros-infrastructure/vcs2l/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.zip
version: vcs2l-377d5b3d03c212f015cc832fdb368f4534d0d583
immutable/tag:
type: git
url: https://github.com/ros-infrastructure/vcs2l.git
version: tags/0.1.27
vcs2l:
type: git
url: https://github.com/ros-infrastructure/vcs2l.git
version: heads/main
without_version:
type: git
url: https://github.com/ros-infrastructure/vcs2l.git
Loading