fix: ship updatable 1.1.1 source archives
Package a clean shallow main checkout with credential-free Gitea remote, localize the China launcher, and set the new-install Responses endpoint.
This commit is contained in:
1 parent
bfcd828fa8
commit
8522fa3ca3
22 files changed
+445
-140
No files matched your search
@@ -59,6 +59,17 @@ def test_save_reload_and_blank_key_preserves_secret(isolated_settings):
|
||||
assert dotenv_values(isolated_settings)["OPENAI_API_KEY"] == "new-test-secret"
|
||||
|
||||
|
||||
def test_new_install_uses_playones_endpoint_without_overriding_saved_url(monkeypatch):
|
||||
monkeypatch.delenv("OPENAI_BASE_URL", raising=False)
|
||||
expected = "https://api-n-cd.playones.com/v1"
|
||||
assert Settings(_env_file=None).OPENAI_BASE_URL == expected
|
||||
assert service.ModelSettingsUpdate(model="test").base_url == expected
|
||||
monkeypatch.setattr(settings, "OPENAI_BASE_URL", None)
|
||||
assert service.get_model_settings()["base_url"] == expected
|
||||
monkeypatch.setattr(settings, "OPENAI_BASE_URL", "https://saved.example/v1")
|
||||
assert service.get_model_settings()["base_url"] == "https://saved.example/v1"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Keep bootstrap scripts ASCII for Windows PowerShell 5.1 compatibility.
|
||||
"""Require ASCII or UTF-8 with BOM for Windows PowerShell 5.1 scripts.
|
||||
|
||||
BOM-less scripts are decoded using the system ANSI code page. UTF-8 symbols
|
||||
can become quote delimiters under cp1252 and cause parse errors.
|
||||
@@ -31,18 +31,11 @@ def test_powershell_scripts_are_discovered():
|
||||
|
||||
|
||||
@pytest.mark.parametrize("script", POWERSHELL_SCRIPTS, ids=lambda p: p.name)
|
||||
def test_powershell_script_is_pure_ascii(script):
|
||||
def test_powershell_script_has_windows_compatible_encoding(script):
|
||||
raw = script.read_bytes()
|
||||
offending = []
|
||||
line_no = 1
|
||||
for index, byte in enumerate(raw):
|
||||
if byte == 0x0A:
|
||||
line_no += 1
|
||||
elif byte > 0x7F:
|
||||
offending.append((line_no, index, hex(byte)))
|
||||
|
||||
assert not offending, (
|
||||
f"{script.name} contains non-ASCII bytes at (line, offset, byte) "
|
||||
f"{offending[:10]}; Windows PowerShell 5.1 decodes BOM-less .ps1 files "
|
||||
"with the system ANSI code page. Use ASCII status labels."
|
||||
)
|
||||
if any(byte > 0x7F for byte in raw):
|
||||
assert raw.startswith(b"\xef\xbb\xbf"), (
|
||||
f"{script.name} contains non-ASCII bytes without a UTF-8 BOM; "
|
||||
"Windows PowerShell 5.1 would use the system ANSI code page."
|
||||
)
|
||||
raw.decode("utf-8-sig")
|
||||
@@ -1,36 +1,134 @@
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import zipfile
|
||||
|
||||
import pytest
|
||||
|
||||
def test_archive_keeps_source_and_excludes_local_builds_and_secrets(tmp_path):
|
||||
script = Path(__file__).resolve().parents[2] / "scripts/package_source.py"
|
||||
spec = importlib.util.spec_from_file_location("package_source", script)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
SCRIPT = Path(__file__).resolve().parents[2] / "scripts/package_source.py"
|
||||
spec = importlib.util.spec_from_file_location("package_source", SCRIPT)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
|
||||
def git(root, *args):
|
||||
result = subprocess.run(
|
||||
["git", "-C", str(root), *args], capture_output=True, text=True, timeout=30
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def repository(tmp_path):
|
||||
if not shutil.which("git"):
|
||||
pytest.skip("Git required")
|
||||
root = tmp_path / "source"
|
||||
root.mkdir()
|
||||
git(root, "init", "-b", "main")
|
||||
git(root, "config", "user.name", "Fixture")
|
||||
git(root, "config", "user.email", "fixture@example.test")
|
||||
keep = ["start.bat", ".env.example", "uv.lock", "apps/showcase_ui/src/main.ts"]
|
||||
tracked_builds = [
|
||||
"artemis/resources/showcase_ui/main.js",
|
||||
"packages/artemis-accessibility-helper/ArtemisAccessibilityHelper.apk",
|
||||
"packages/artemis-accessibility-helper/debug.keystore",
|
||||
]
|
||||
omit = [
|
||||
".env",
|
||||
".env.local",
|
||||
".venv/pyvenv.cfg",
|
||||
"nested/node_modules/foo.js",
|
||||
"apps/showcase_ui/dist/main.js",
|
||||
"artemis/resources/showcase_ui/main.js",
|
||||
"__pycache__/a.pyc",
|
||||
"traces/data.db",
|
||||
"helper.apk",
|
||||
"debug.keystore",
|
||||
".git/config",
|
||||
".roo/mcp.json",
|
||||
]
|
||||
for name in keep + omit:
|
||||
target = tmp_path / name
|
||||
for name in keep + tracked_builds + omit:
|
||||
target = root / name
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text("fixture")
|
||||
(root / ".gitignore").write_text(
|
||||
".env*\n!.env.example\n.venv/\nnode_modules/\ndist/\ntraces/\n.roo/\n__pycache__/\n"
|
||||
)
|
||||
git(root, "add", "--", ".gitignore", *keep, *tracked_builds)
|
||||
git(root, "commit", "-m", "initial")
|
||||
git(root, "remote", "add", "eapil", "https://git.example.invalid/team/project.git")
|
||||
git(root, "config", "branch.main.remote", "eapil")
|
||||
git(root, "config", "branch.main.merge", "refs/heads/main")
|
||||
return root, keep, tracked_builds, omit
|
||||
|
||||
|
||||
def test_archive_is_updatable_clean_checkout_without_local_data(repository, tmp_path):
|
||||
root, keep, tracked_builds, omit = repository
|
||||
output = tmp_path / "artifacts/source.zip"
|
||||
count, digest = module.package_source(tmp_path, output)
|
||||
assert count == len(keep)
|
||||
count, digest = module.package_source(root, output)
|
||||
assert count > len(keep)
|
||||
assert len(digest) == 64
|
||||
with zipfile.ZipFile(output) as archive:
|
||||
assert archive.testzip() is None
|
||||
assert set(archive.namelist()) == {f"artemis/{name}" for name in keep}
|
||||
names = set(archive.namelist())
|
||||
assert {f"artemis/{name}" for name in keep}.issubset(names)
|
||||
assert not {f"artemis/{name}" for name in tracked_builds + omit} & names
|
||||
assert "artemis/.git/config" in names
|
||||
assert "artemis/.git/index" in names
|
||||
assert not any(name.startswith("artemis/.git/logs/") for name in names)
|
||||
assert not any(name.startswith("artemis/.git/hooks/") for name in names)
|
||||
archive.extractall(tmp_path / "unpacked")
|
||||
extracted = tmp_path / "unpacked/artemis"
|
||||
assert git(extracted, "symbolic-ref", "--short", "HEAD") == "main"
|
||||
assert git(extracted, "rev-parse", "HEAD") == git(root, "rev-parse", "HEAD")
|
||||
assert git(extracted, "status", "--porcelain") == ""
|
||||
assert git(extracted, "remote", "get-url", "origin") == (
|
||||
"https://git.example.invalid/team/project.git"
|
||||
)
|
||||
assert git(extracted, "config", "--get", "branch.main.remote") == "origin"
|
||||
(extracted / tracked_builds[0]).parent.mkdir(parents=True)
|
||||
(extracted / tracked_builds[0]).write_text("new bundle")
|
||||
assert git(extracted, "status", "--porcelain") == ""
|
||||
|
||||
|
||||
def test_unpacked_archive_fast_forwards(repository, tmp_path):
|
||||
root, _, tracked_builds, _ = repository
|
||||
bare = tmp_path / "upstream.git"
|
||||
bare.mkdir()
|
||||
git(bare, "init", "--bare")
|
||||
git(root, "remote", "add", "test-upstream", str(bare))
|
||||
git(root, "push", "test-upstream", "main")
|
||||
archive = tmp_path / "source.zip"
|
||||
module.package_source(root, archive)
|
||||
with zipfile.ZipFile(archive) as contents:
|
||||
contents.extractall(tmp_path / "unpacked")
|
||||
extracted = tmp_path / "unpacked/artemis"
|
||||
git(extracted, "remote", "set-url", "origin", str(bare))
|
||||
built_asset = extracted / tracked_builds[0]
|
||||
built_asset.parent.mkdir(parents=True)
|
||||
built_asset.write_text("generated after setup")
|
||||
(root / "start.bat").write_text("updated")
|
||||
git(root, "add", "--", "start.bat")
|
||||
git(root, "commit", "-m", "update launcher")
|
||||
git(root, "push", "test-upstream", "main")
|
||||
from scripts.update_installation import update_source
|
||||
|
||||
assert update_source(extracted, port=1) == 10
|
||||
assert (extracted / "start.bat").read_text() == "updated"
|
||||
assert git(extracted, "status", "--porcelain") == ""
|
||||
|
||||
|
||||
def test_packaging_rejects_uncommitted_changes_and_credentials(repository, tmp_path):
|
||||
root, _, _, _ = repository
|
||||
(root / "start.bat").write_text("local change")
|
||||
with pytest.raises(ValueError, match="Commit tracked changes"):
|
||||
module.package_source(root, tmp_path / "source.zip")
|
||||
(root / "start.bat").write_text("fixture")
|
||||
git(
|
||||
root,
|
||||
"remote",
|
||||
"set-url",
|
||||
"eapil",
|
||||
"https://user:secret@git.example.invalid/team/project.git",
|
||||
)
|
||||
with pytest.raises(ValueError, match="credential-free HTTPS"):
|
||||
module.package_source(root, tmp_path / "source.zip")
|
||||
Reference in new issue
Block a user