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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Unreleased

- Make development bootstrap repair a stale globally registered coverage repository URL before
selecting it for the repository-local switch.

## [1.1.0] - 2026-08-26

- Reset the scenario, journal, strategy, execution-configuration, CLI, and diagnostic contracts to
Expand Down
17 changes: 13 additions & 4 deletions scripts/bootstrap-development-environment
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,19 @@ if [ ! -f "$repository_root/_opam/.opam-switch/switch-config" ]; then
fi

printf '%s\n' "Registering the checksummed OCaml coverage package..."
opam repository add "$coverage_repository_name" "$coverage_repository" \
--rank 1 \
--switch "$repository_root" \
--yes
if opam repository list --all --short --color never 2>/dev/null \
| grep -Fqx "$coverage_repository_name"; then
opam repository set-url "$coverage_repository_name" "$coverage_repository" --yes
opam repository add "$coverage_repository_name" \
--rank 1 \
--switch "$repository_root" \
--yes
else
opam repository add "$coverage_repository_name" "$coverage_repository" \
--rank 1 \
--switch "$repository_root" \
--yes
fi

if opam pin list --switch "$repository_root" --short | grep -Fqx "bisect_ppx"; then
opam pin remove bisect_ppx \
Expand Down
1 change: 1 addition & 0 deletions test/dune
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
(alias runtest)
(deps
test_development_environment.py
../scripts/bootstrap-development-environment
../scripts/check-schema-environment.py)
(action
(run python3 %{dep:test_development_environment.py})))
Expand Down
91 changes: 91 additions & 0 deletions test/test_development_environment.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import annotations

import importlib.util
import os
import pathlib
import shutil
import subprocess
import tempfile
import unittest

Expand Down Expand Up @@ -53,5 +56,93 @@ def test_reports_missing_mismatched_and_unexpected_packages(self) -> None:
)


class BootstrapEnvironmentTest(unittest.TestCase):
def test_repairs_a_registered_repository_before_selecting_it(self) -> None:
result, commands, repository_root = self.run_bootstrap(repository_registered=True)

self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(
f"repository set-url trading-engine-coverage {repository_root / 'opam-repository'} --yes",
commands,
)
self.assertIn(
"repository add trading-engine-coverage --rank 1 "
f"--switch {repository_root} --yes",
commands,
)

def test_registers_a_missing_repository_with_its_local_url(self) -> None:
result, commands, repository_root = self.run_bootstrap(repository_registered=False)

self.assertEqual(result.returncode, 0, result.stderr)
self.assertFalse(any("repository set-url" in command for command in commands))
self.assertIn(
"repository add trading-engine-coverage "
f"{repository_root / 'opam-repository'} --rank 1 "
f"--switch {repository_root} --yes",
commands,
)

def run_bootstrap(
self, *, repository_registered: bool
) -> tuple[subprocess.CompletedProcess[str], list[str], pathlib.Path]:
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
repository_root = pathlib.Path(temporary.name)
scripts = repository_root / "scripts"
scripts.mkdir()
bootstrap = scripts / "bootstrap-development-environment"
shutil.copy2(REPOSITORY_ROOT / "scripts" / bootstrap.name, bootstrap)
self.write_executable(
scripts / "check-development-environment", "#!/bin/sh\nexit 0\n"
)
(repository_root / "_opam/.opam-switch").mkdir(parents=True)
(repository_root / "_opam/.opam-switch/switch-config").touch()
schema_bin = repository_root / ".venv-schema/bin"
schema_bin.mkdir(parents=True)
self.write_executable(schema_bin / "python", "#!/bin/sh\nexit 0\n")
(repository_root / "requirements").mkdir()
(repository_root / "requirements/schema.lock").touch()
(repository_root / "opam-repository").mkdir()

fake_bin = repository_root / "fake-bin"
fake_bin.mkdir()
opam_log = repository_root / "opam.log"
self.write_executable(
fake_bin / "opam",
"#!/bin/sh\n"
'printf \'%s\\n\' "$*" >> "$OPAM_LOG"\n'
'if [ "$1" = repository ] && [ "$2" = list ] '
'&& [ "$REPOSITORY_REGISTERED" = 1 ]; then\n'
" printf '%s\\n' trading-engine-coverage\n"
"fi\n",
)
self.write_executable(fake_bin / "uv", "#!/bin/sh\nexit 0\n")
self.write_executable(fake_bin / "python3", "#!/bin/sh\nexit 0\n")
environment = os.environ.copy()
environment.update(
{
"OPAM_LOG": str(opam_log),
"PATH": f"{fake_bin}:{environment['PATH']}",
"REPOSITORY_REGISTERED": "1" if repository_registered else "0",
}
)

result = subprocess.run(
[str(bootstrap)],
cwd=repository_root,
env=environment,
check=False,
capture_output=True,
text=True,
)
return result, opam_log.read_text(encoding="utf-8").splitlines(), repository_root

@staticmethod
def write_executable(path: pathlib.Path, contents: str) -> None:
path.write_text(contents, encoding="utf-8")
path.chmod(0o755)


if __name__ == "__main__":
unittest.main()
Loading