Update package version to 0.0.1-beta, add new dependencies including ExcelJS, and refactor export utilities to utilize ExcelJS for Excel file generation. Enhance component JSON files with vendor information for improved asset management.

This commit is contained in:
2026-01-07 02:12:12 +00:00
parent 4bc0fd203f
commit 97d2b66f02
33 changed files with 4394 additions and 1088 deletions

1
tests/__init__.py Normal file
View File

@@ -0,0 +1 @@
# Tests package

240
tests/test_check_updates.py Normal file
View File

@@ -0,0 +1,240 @@
#!/usr/bin/env python3
"""
Tests for check_updates.py
"""
import json
import sys
import tempfile
from pathlib import Path
from unittest.mock import patch
import pytest
import responses
# Import the module
sys.path.insert(0, str(Path(__file__).parent.parent / 'scripts'))
from check_updates import GitHubAPI, check_entry
@pytest.fixture
def github_api():
"""Create a GitHubAPI instance for testing."""
return GitHubAPI(token='test-token')
@pytest.fixture
def sample_manifest_entry():
"""Sample manifest entry for testing."""
return {
'id': 'test-entry',
'source_repo': 'owner/repo',
'source_path': 'path/to/file.stl',
'source_ref': 'main',
'pinned_sha': 'pinned-sha-123',
'pinned_raw_url': 'https://raw.githubusercontent.com/owner/repo/pinned-sha-123/path/to/file.stl',
'local_path': 'vendor/owner-repo/path/to/file.stl',
'checksum_sha256': 'abc123',
'last_checked': '2024-01-01T00:00:00Z',
'upstream_latest_sha': None,
'status': 'unknown',
'license': None
}
@responses.activate
def test_check_entry_up_to_date(github_api, sample_manifest_entry):
"""Test checking an entry that is up-to-date."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
pinned_sha = 'pinned-sha-123'
# Mock commits API - return same SHA as pinned
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': pinned_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
updated_entry = check_entry(sample_manifest_entry, github_api)
assert updated_entry['status'] == 'up-to-date'
assert updated_entry['upstream_latest_sha'] == pinned_sha
assert updated_entry['last_checked'] is not None
@responses.activate
def test_check_entry_out_of_date(github_api, sample_manifest_entry):
"""Test checking an entry that is out-of-date."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
pinned_sha = 'pinned-sha-123'
latest_sha = 'latest-sha-456'
# Mock commits API - return different SHA
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': latest_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
updated_entry = check_entry(sample_manifest_entry, github_api)
assert updated_entry['status'] == 'out-of-date'
assert updated_entry['upstream_latest_sha'] == latest_sha
assert updated_entry['pinned_sha'] == pinned_sha # Pinned SHA unchanged
assert updated_entry['last_checked'] is not None
@responses.activate
def test_check_entry_no_pinned_sha(github_api):
"""Test checking an entry with no pinned SHA."""
entry = {
'id': 'test-entry',
'source_repo': 'owner/repo',
'source_path': 'path/to/file.stl',
'source_ref': 'main',
'pinned_sha': None,
'status': 'unknown'
}
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
latest_sha = 'latest-sha-456'
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': latest_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
updated_entry = check_entry(entry, github_api)
assert updated_entry['status'] == 'unknown'
assert updated_entry['upstream_latest_sha'] == latest_sha
@responses.activate
def test_check_entry_api_error(github_api, sample_manifest_entry):
"""Test handling of API errors."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
# Mock API error
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
status=500
)
updated_entry = check_entry(sample_manifest_entry, github_api)
assert updated_entry['status'] == 'unknown'
assert updated_entry['upstream_latest_sha'] is None
@responses.activate
def test_check_entry_file_not_found(github_api, sample_manifest_entry):
"""Test handling when file doesn't exist at ref."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
# Mock empty commits response (file doesn't exist)
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
updated_entry = check_entry(sample_manifest_entry, github_api)
# Should still update last_checked but status might be unknown
assert updated_entry['last_checked'] is not None
def test_github_api_get_latest_commit_sha(github_api):
"""Test getting latest commit SHA."""
owner = 'owner'
repo = 'repo'
path = 'file.stl'
ref = 'main'
expected_sha = 'commit-sha-789'
with responses.RequestsMock() as rsps:
rsps.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': expected_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
sha = github_api.get_latest_commit_sha(owner, repo, path, ref)
assert sha == expected_sha
def test_github_api_get_latest_commit_sha_ref_is_sha(github_api):
"""Test when ref is already a SHA."""
owner = 'owner'
repo = 'repo'
path = 'file.stl'
ref = 'a' * 40 # Valid SHA format
# Should return the ref as-is if it's already a SHA
sha = github_api.get_latest_commit_sha(owner, repo, path, ref)
# Actually, the function tries to get commits first, so it will make an API call
# But if ref is a SHA, it should work
with responses.RequestsMock() as rsps:
rsps.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': ref}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
sha = github_api.get_latest_commit_sha(owner, repo, path, ref)
assert sha == ref
if __name__ == '__main__':
pytest.main([__file__, '-v'])

317
tests/test_vendor_update.py Normal file
View File

@@ -0,0 +1,317 @@
#!/usr/bin/env python3
"""
Tests for vendor_update.py
"""
import hashlib
import json
import tempfile
from pathlib import Path
from unittest.mock import Mock, patch, mock_open
import pytest
import responses
# Import the module (adjust path as needed)
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / 'scripts'))
from vendor_update import GitHubAPI, compute_sha256, download_file, update_manifest_entry
@pytest.fixture
def temp_dir():
"""Create a temporary directory for tests."""
with tempfile.TemporaryDirectory() as tmpdir:
yield Path(tmpdir)
@pytest.fixture
def sample_manifest_entry():
"""Sample manifest entry for testing."""
return {
'id': 'test-entry',
'source_repo': 'owner/repo',
'source_path': 'path/to/file.stl',
'source_ref': 'main',
'pinned_sha': None,
'pinned_raw_url': None,
'local_path': 'vendor/owner-repo/path/to/file.stl',
'checksum_sha256': None,
'last_checked': None,
'upstream_latest_sha': None,
'status': 'unknown',
'license': None
}
@pytest.fixture
def github_api():
"""Create a GitHubAPI instance for testing."""
return GitHubAPI(token='test-token')
def test_compute_sha256(temp_dir):
"""Test SHA256 computation."""
test_file = temp_dir / 'test.txt'
test_file.write_text('test content')
checksum = compute_sha256(test_file)
# Verify it's a valid SHA256 hex string
assert len(checksum) == 64
assert all(c in '0123456789abcdef' for c in checksum.lower())
# Verify it matches expected hash
expected = hashlib.sha256(b'test content').hexdigest()
assert checksum == expected
@responses.activate
def test_download_file_success(temp_dir):
"""Test successful file download."""
test_url = 'https://example.com/file.stl'
test_content = b'STL file content'
dest_path = temp_dir / 'downloaded.stl'
responses.add(
responses.GET,
test_url,
body=test_content,
status=200
)
result = download_file(test_url, dest_path)
assert result is True
assert dest_path.exists()
assert dest_path.read_bytes() == test_content
@responses.activate
def test_download_file_failure():
"""Test file download failure."""
test_url = 'https://example.com/missing.stl'
dest_path = Path('/tmp/test.stl')
responses.add(
responses.GET,
test_url,
status=404
)
result = download_file(test_url, dest_path)
assert result is False
@responses.activate
def test_github_api_get_file_sha(github_api):
"""Test getting file SHA from GitHub API."""
owner = 'test-owner'
repo = 'test-repo'
path = 'file.stl'
ref = 'main'
# Mock Contents API response
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
json={'sha': 'blob-sha-123'},
match=[responses.matchers.query_param_matcher({'ref': ref})]
)
# Mock Commits API response
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': 'commit-sha-456'}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
sha = github_api.get_file_sha(owner, repo, path, ref)
assert sha == 'commit-sha-456'
@responses.activate
def test_github_api_get_license(github_api):
"""Test getting license information."""
owner = 'test-owner'
repo = 'test-repo'
sha = 'abc123'
# Mock LICENSE file found
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/contents/LICENSE',
json={'type': 'file'},
match=[responses.matchers.query_param_matcher({'ref': sha})]
)
license_url = github_api.get_license(owner, repo, sha)
assert license_url == f'https://raw.githubusercontent.com/{owner}/{repo}/{sha}/LICENSE'
@responses.activate
def test_update_manifest_entry_dry_run(temp_dir, sample_manifest_entry):
"""Test updating manifest entry in dry-run mode."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
# Mock API responses
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
json={'sha': 'blob-sha'},
match=[responses.matchers.query_param_matcher({'ref': ref})]
)
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': 'commit-sha-123'}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
api = GitHubAPI(token='test-token')
updated_entry = update_manifest_entry(
sample_manifest_entry,
api,
temp_dir,
dry_run=True
)
assert updated_entry['pinned_sha'] == 'commit-sha-123'
assert updated_entry['pinned_raw_url'] == f'https://raw.githubusercontent.com/{owner}/{repo}/commit-sha-123/{path}'
assert updated_entry['status'] == 'up-to-date'
assert updated_entry['last_checked'] is not None
assert updated_entry['upstream_latest_sha'] == 'commit-sha-123'
# In dry-run, file should not be downloaded
local_path = temp_dir / updated_entry['local_path']
assert not local_path.exists()
@responses.activate
def test_update_manifest_entry_with_download(temp_dir, sample_manifest_entry):
"""Test updating manifest entry with actual download."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
commit_sha = 'commit-sha-123'
file_content = b'STL file content here'
# Mock API responses
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
json={'sha': 'blob-sha'},
match=[responses.matchers.query_param_matcher({'ref': ref})]
)
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': commit_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
# Mock file download
pinned_url = f'https://raw.githubusercontent.com/{owner}/{repo}/{commit_sha}/{path}'
responses.add(
responses.GET,
pinned_url,
body=file_content,
status=200
)
api = GitHubAPI(token='test-token')
updated_entry = update_manifest_entry(
sample_manifest_entry,
api,
temp_dir,
dry_run=False
)
assert updated_entry['pinned_sha'] == commit_sha
assert updated_entry['checksum_sha256'] is not None
assert updated_entry['status'] == 'up-to-date'
# Verify file was downloaded
local_path = temp_dir / updated_entry['local_path']
assert local_path.exists()
assert local_path.read_bytes() == file_content
# Verify checksum
expected_checksum = hashlib.sha256(file_content).hexdigest()
assert updated_entry['checksum_sha256'] == expected_checksum
@responses.activate
def test_update_manifest_entry_download_failure(temp_dir, sample_manifest_entry):
"""Test handling of download failure."""
owner = 'owner'
repo = 'repo'
path = 'path/to/file.stl'
ref = 'main'
commit_sha = 'commit-sha-123'
# Mock API responses
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
json={'sha': 'blob-sha'},
match=[responses.matchers.query_param_matcher({'ref': ref})]
)
responses.add(
responses.GET,
f'https://api.github.com/repos/{owner}/{repo}/commits',
json=[{'sha': commit_sha}],
match=[responses.matchers.query_param_matcher({
'path': path,
'sha': ref,
'per_page': 1
})]
)
# Mock file download failure
pinned_url = f'https://raw.githubusercontent.com/{owner}/{repo}/{commit_sha}/{path}'
responses.add(
responses.GET,
pinned_url,
status=404
)
api = GitHubAPI(token='test-token')
updated_entry = update_manifest_entry(
sample_manifest_entry,
api,
temp_dir,
dry_run=False
)
assert updated_entry['status'] == 'error'
assert updated_entry['pinned_sha'] == commit_sha # SHA was resolved
assert updated_entry['checksum_sha256'] is None # File not downloaded
if __name__ == '__main__':
pytest.main([__file__, '-v'])