mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 20:26:33 +00:00
Every stack answered to *.infinito.test, and the host resolver pointed that zone at 127.0.0.1, so a worktree's stack on its own bind IP could not be opened in a browser while the primary stack existed. INFINITO_DOMAIN is now derived per checkout: main.infinito.test for the primary one, and for a linked worktree its branch, lowercased with everything outside a-z0-9_- turned into "-", below INFINITO_DNS_DOMAIN (feature/store-i18n -> feature-store-i18n.infinito.test). The branch is read from the worktree's gitdir HEAD instead of running git, because git refuses the mounted checkout inside the stack container. GitHub and act runs keep the static default, custom.env still wins. The handler overrides the caller's value on purpose: inside the stack container that value is the previous .env, which make setup rewrote on every deploy, so the old domain kept feeding itself back into the next compose up. make network-dns-setup routes each stack's domain to the INFINITO_BIND_IP in that checkout's .env, with a local= line so AAAA answers NODATA instead of the primary stack's ::1. It skips domains outside the base zone, which a stale .env still carries, and fails when two checkouts claim one domain. worktree-up prints the domain and the follow-up command. Existing checkouts switch after make dotenv-force and a redeploy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
113 lines
3.3 KiB
Python
113 lines
3.3 KiB
Python
"""Unit tests for :mod:`utils.env.handlers.infinito.domain`."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import os
|
|
import subprocess
|
|
import unittest
|
|
from contextlib import redirect_stderr
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
from unittest.mock import patch
|
|
|
|
from utils.env.builder import BuildContext, EnvBuilder
|
|
from utils.env.handlers.infinito import domain as handler
|
|
|
|
_GIT = [
|
|
"git",
|
|
"-c",
|
|
"user.name=t",
|
|
"-c",
|
|
"user.email=t@t",
|
|
"-c",
|
|
"commit.gpgSign=false",
|
|
]
|
|
|
|
|
|
def _git(repo: Path, *args: str) -> None:
|
|
subprocess.run([*_GIT, "-C", str(repo), *args], check=True, capture_output=True)
|
|
|
|
|
|
def _repository(root: Path) -> Path:
|
|
repo = root / "repo"
|
|
repo.mkdir()
|
|
_git(repo, "init", "-q", "-b", "main")
|
|
_git(repo, "commit", "-q", "--allow-empty", "-m", "init")
|
|
return repo
|
|
|
|
|
|
def _worktree(repo: Path, branch: str) -> Path:
|
|
path = repo.parent / "worktree"
|
|
_git(repo, "worktree", "add", "-q", "-b", branch, str(path))
|
|
return path
|
|
|
|
|
|
def _apply(
|
|
repo_root: Path, *, on_gha: bool = False, on_act: bool = False
|
|
) -> str | None:
|
|
ctx = BuildContext(
|
|
static={},
|
|
static_comments={},
|
|
repo_root=repo_root,
|
|
on_gha=on_gha,
|
|
on_act=on_act,
|
|
)
|
|
eb = EnvBuilder()
|
|
eb.set("INFINITO_DNS_DOMAIN", "infinito.test")
|
|
handler.apply(eb, ctx)
|
|
return eb.values.get(handler.KEY)
|
|
|
|
|
|
class TestDomain(unittest.TestCase):
|
|
def test_primary_checkout_is_main(self) -> None:
|
|
with TemporaryDirectory() as td:
|
|
self.assertEqual(_apply(_repository(Path(td))), "main.infinito.test")
|
|
|
|
def test_directory_without_git_is_main(self) -> None:
|
|
with TemporaryDirectory() as td:
|
|
self.assertEqual(_apply(Path(td)), "main.infinito.test")
|
|
|
|
def test_worktree_is_its_normalised_branch(self) -> None:
|
|
with TemporaryDirectory() as td:
|
|
worktree = _worktree(_repository(Path(td)), "Feature/Store_I18n.v2")
|
|
|
|
self.assertEqual(_apply(worktree), "feature-store_i18n-v2.infinito.test")
|
|
|
|
def test_worktree_with_unreachable_git_directory_keeps_the_default(
|
|
self,
|
|
) -> None:
|
|
with TemporaryDirectory() as td:
|
|
checkout = Path(td)
|
|
(checkout / ".git").write_text(
|
|
"gitdir: /host/only/.git/worktrees/x\n", encoding="utf-8"
|
|
)
|
|
stderr = io.StringIO()
|
|
|
|
with redirect_stderr(stderr):
|
|
self.assertIsNone(_apply(checkout))
|
|
|
|
self.assertIn("not reachable", stderr.getvalue())
|
|
|
|
def test_branch_too_long_for_a_dns_label_fails(self) -> None:
|
|
with TemporaryDirectory() as td:
|
|
worktree = _worktree(_repository(Path(td)), "a" * 64)
|
|
|
|
with self.assertRaises(SystemExit):
|
|
_apply(worktree)
|
|
|
|
def test_stale_caller_value_is_replaced_but_ci_runs_keep_the_default(
|
|
self,
|
|
) -> None:
|
|
with TemporaryDirectory() as td:
|
|
worktree = _worktree(_repository(Path(td)), "feature/x")
|
|
|
|
with patch.dict(os.environ, {handler.KEY: "infinito.test"}):
|
|
self.assertEqual(_apply(worktree), "feature-x.infinito.test")
|
|
self.assertIsNone(_apply(worktree, on_gha=True))
|
|
self.assertIsNone(_apply(worktree, on_act=True))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|