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
13 changes: 9 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,13 @@ def submodule_update_through_git(root: Path, remotes: Path,
# the remote, each run `git maintenance run --auto` as they finish. Since git
# 2.47 that run DETACHES, holding `objects/maintenance.lock`, and the command
# returns while it goes on; since 2.54 its default strategy (`geometric`)
# repacks a repository of a few hundred loose objects and deletes the ones
# repacks once its estimate, taken from `objects/17` alone, is above 256
# loose objects, so two loose objects there are enough, and deletes the ones
# it packed. A copy taken in that moment fails `[Errno 2] No such file or
# directory` on one of them: `holder` and `the_standard_moved`, on the
# Linux runner (#645).
# directory` on one of them (`holder` and `the_standard_moved`, on the
# Linux runner, #645), and a listing of `.git/objects` taken before and
# after it differs: `test_family_bump_remove_rollback.py`'s `objects
# changed`, 37 loose objects packed into two.
#
# So the session turns it off, as every git command in this estate is told
# to: `gc.auto=0`, for a git that runs `git gc --auto` itself (2.43's
Expand Down Expand Up @@ -262,7 +265,9 @@ def submodule_update_through_git(root: Path, remotes: Path,
# `GIT_CONFIG_GLOBAL` of a test's own, or an environment built from nothing
# -- and a push made under a global file of a test's own. No repository the
# suite copies is made, or pushed to, that way today.
# `tests/test_no_auto_maintenance.py` holds both scopes to account.
# `tests/test_no_auto_maintenance.py` holds both scopes to account, and fails a
# test file that sets `GIT_CONFIG_COUNT` to a number of its own instead of
# appending (#758).

#: The two settings, in the order they are appended and written.
NO_AUTO_MAINTENANCE = (("gc.auto", "0"), ("maintenance.auto", "false"))
Expand Down
40 changes: 24 additions & 16 deletions tests/test_adopt_empty_symlinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from __future__ import annotations

import importlib.util
import os
import re
import shutil
import subprocess
Expand All @@ -44,8 +45,8 @@

import pytest

from conftest import ADOPT, as_human, git, make_source_repo, run_script, \
write_plan
from conftest import (ADOPT, appended_to_command_scope, as_human, git,
make_source_repo, run_script, write_plan)

needs_filter_repo = pytest.mark.skipif(
shutil.which("git-filter-repo") is None,
Expand All @@ -68,10 +69,15 @@
#: The issue's small source: a spec, the code, and a README the root keeps.
TREE = {"src/app.py": "print(1)\n", "docs/spec.md": "# Spec\n",
"README.md": "# Thing\n"}
#: `core.symlinks=false` for every git a run starts, as Git for Windows has it
#: by default.
SYMLINKS_OFF = {"GIT_CONFIG_COUNT": "1", "GIT_CONFIG_KEY_0": "core.symlinks",
"GIT_CONFIG_VALUE_0": "false"}


def symlinks_off() -> dict:
"""`core.symlinks=false` for every git a run starts, as Git for Windows
has it by default: appended, when it is called, to the git command scope
the environment holds (#758)."""
return appended_to_command_scope(os.environ, [("core.symlinks", "false")])


#: The issue's target (#388): 8 bytes, the first of them NUL, so Linux reads
#: it as the empty target.
NUL_LED = b"\0spec.md"
Expand Down Expand Up @@ -387,8 +393,8 @@ def test_check_reports_it_where_git_makes_no_symlinks_too(tmp_path, target,
so `core.symlinks=false` changes nothing it says."""
plan = planned(source_with_links(tmp_path, "docs/empty-link",
target=target),
tmp_path / "plan.yaml", env=SYMLINKS_OFF)
off, on = check(plan, env=SYMLINKS_OFF), check(plan)
tmp_path / "plan.yaml", env=symlinks_off())
off, on = check(plan, env=symlinks_off()), check(plan)
assert off.returncode == on.returncode == 1
assert findings_of(off) == findings_of(on)
finding, = findings_of(off)
Expand Down Expand Up @@ -461,21 +467,22 @@ def test_execute_refuses_it_before_any_leg_exists(

@needs_filter_repo
@with_each_target
@pytest.mark.parametrize("env", [
pytest.param(None, id="symlinks-on"),
pytest.param(SYMLINKS_OFF, id="symlinks-off"),
@pytest.mark.parametrize("off", [
pytest.param(False, id="symlinks-on"),
pytest.param(True, id="symlinks-off"),
])
@pytest.mark.parametrize("link, answers", [
pytest.param("docs/empty-link", {}, id="in-docs"),
pytest.param("empty-link", {"empty-link": "drop"}, id="top-level-drop"),
])
def test_execute_refuses_it_end_to_end_and_the_remote_dir_stays_empty(
tmp_path, env, link, answers, target, words):
tmp_path, off, link, answers, target, words):
"""The issue's runs as commands: on main, both leg repositories and exit
2 (symlinks on; with nothing said, until #171's fix said what failed), or
`adoption verified` over a leg no clone with symlinks on can check out
(symlinks off). Refused before a leg is made, so the EMPTY
`--local-remote-dir` stays empty."""
env = symlinks_off() if off else None
source = source_with_links(tmp_path, link, target=target)
plan = planned(source, tmp_path / "plan.yaml", answers, env=env)
(tmp_path / REMOTES).mkdir()
Expand All @@ -502,16 +509,17 @@ def test_the_link_removed_in_the_source_adopts_end_to_end(tmp_path):


@needs_filter_repo
@pytest.mark.parametrize("env", [
pytest.param(None, id="symlinks-on", marks=needs_disk_symlinks),
pytest.param(SYMLINKS_OFF, id="symlinks-off"),
@pytest.mark.parametrize("off", [
pytest.param(False, id="symlinks-on", marks=needs_disk_symlinks),
pytest.param(True, id="symlinks-off"),
])
def test_the_link_given_a_target_adopts_end_to_end(tmp_path, env):
def test_the_link_given_a_target_adopts_end_to_end(tmp_path, off):
"""The other remediation, and #388's control: a target that names
something (`spec.md`, 7 bytes), read now, is no finding. With symlinks
on, `execute`'s clones check the link out, so this needs a platform
that makes symlinks; with them off, the clones hold it as a file. Either
way the leg holds the link."""
env = symlinks_off() if off else None
source = source_with_links(tmp_path, "docs/empty-link")
put_link(source, "docs/empty-link", NAMED)
as_human("commit", "-qm", "Give the link a target", cwd=source)
Expand Down
17 changes: 7 additions & 10 deletions tests/test_adopt_git_reads.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

import pytest

from conftest import REPO, git, make_source_repo
from conftest import REPO, appended_to_command_scope, git, make_source_repo
from test_adopt_template_values import (ADOPT_REFUSED, PLAN_FILE, PLAN_OK,
PROJECT, REMOTES, SPLIT_BRANCH,
VERIFIED, WORK, adopted, answer,
Expand Down Expand Up @@ -111,10 +111,8 @@ def command_scope(key: str, value: bytes) -> dict:
The value goes in as the bytes it is, through `os.fsdecode`, which is how
`sys.argv` and `os.environ` carry a byte that is not UTF-8 on POSIX. A
Windows environment is text, so the caller does not use this there."""
held = int(os.environ.get("GIT_CONFIG_COUNT") or 0)
return {"GIT_CONFIG_COUNT": str(held + 1),
f"GIT_CONFIG_KEY_{held}": key,
f"GIT_CONFIG_VALUE_{held}": os.fsdecode(value)}
return appended_to_command_scope(os.environ,
[(key, os.fsdecode(value))])


def global_user_name(base: Path, name: bytes) -> dict:
Expand Down Expand Up @@ -200,11 +198,10 @@ def test_the_user_name_given_is_appended_to_the_config_the_environment_holds(
drop both, and every test after it would run with git's own line-end and
long-path defaults. The two slots here are the job's, under keys no
config of a machine this runs on sets."""
for variable, value in {"GIT_CONFIG_COUNT": "2",
"GIT_CONFIG_KEY_0": "test.heldone",
"GIT_CONFIG_VALUE_0": "one",
"GIT_CONFIG_KEY_1": "test.heldtwo",
"GIT_CONFIG_VALUE_1": "two"}.items():
held = appended_to_command_scope(
{}, [("test.heldone", "one"), ("test.heldtwo", "two")])
assert held["GIT_CONFIG_COUNT"] == "2", held
for variable, value in held.items():
monkeypatch.setenv(variable, value)
extra = global_user_name(tmp_path, LATIN1_NAME)
assert extra["GIT_CONFIG_COUNT"] == "3", extra
Expand Down
11 changes: 5 additions & 6 deletions tests/test_adopt_ignored_shape_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@

import pytest

from conftest import (ADOPT, REPO, clear_ambient_pin_sources,
cloned_just_pushed, git, make_source_repo, resolve,
run_script, write_plan)
from conftest import (ADOPT, REPO, appended_to_command_scope,
clear_ambient_pin_sources, cloned_just_pushed, git,
make_source_repo, resolve, run_script, write_plan)

sys.path.insert(0, str(REPO / "scripts"))
from repo_shape import parse_yaml # noqa: E402
Expand Down Expand Up @@ -582,9 +582,8 @@ def command_scope(key: str, value: str) -> dict:
`core.autocrlf=false` there, which outranks any config file, so a
clone's own `--config` would not reach its checkout. The last entry of a
key is the one git reads."""
held = int(os.environ.get("GIT_CONFIG_COUNT") or 0)
return {**os.environ, "GIT_CONFIG_COUNT": str(held + 1),
f"GIT_CONFIG_KEY_{held}": key, f"GIT_CONFIG_VALUE_{held}": value}
return {**os.environ,
**appended_to_command_scope(os.environ, [(key, value)])}


@needs_filter_repo
Expand Down
10 changes: 4 additions & 6 deletions tests/test_adopt_nested_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@

import pytest

from conftest import (ADOPT, REPO, clone_just_pushed, findings, git,
make_source_repo, planned, refused_before_any_leg,
run_script)
from conftest import (ADOPT, REPO, appended_to_command_scope,
clone_just_pushed, findings, git, make_source_repo,
planned, refused_before_any_leg, run_script)

sys.path.insert(0, str(REPO / "scripts"))
from repo_shape import parse_yaml # noqa: E402
Expand Down Expand Up @@ -383,9 +383,7 @@ def command_scope(key: str, value: str) -> dict:
"""`key=value` in git's command scope (`GIT_CONFIG_COUNT`), appended to
what the environment holds: the Windows job sets `core.autocrlf` there,
and the last entry of a key is the one git reads."""
held = int(os.environ.get("GIT_CONFIG_COUNT") or 0)
return {"GIT_CONFIG_COUNT": str(held + 1),
f"GIT_CONFIG_KEY_{held}": key, f"GIT_CONFIG_VALUE_{held}": value}
return appended_to_command_scope(os.environ, [(key, value)])


def checked(plan: Path, env: dict):
Expand Down
10 changes: 6 additions & 4 deletions tests/test_adopt_plan_yaml_quoting.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import functools
import importlib.util
import itertools
import os
import random
import re
import shutil
Expand All @@ -74,8 +75,9 @@

import pytest

from conftest import (ADOPT, REPO, cloned_just_pushed, git, make_source_repo,
resolve, run_script, write_plan)
from conftest import (ADOPT, REPO, appended_to_command_scope,
cloned_just_pushed, git, make_source_repo, resolve,
run_script, write_plan)

sys.path.insert(0, str(REPO / "scripts"))
import repo_shape # noqa: E402
Expand Down Expand Up @@ -941,8 +943,8 @@ def test_plan_takes_an_elector_from_git_the_manifests_quotes_read_back(
result = run_script(
ADOPT, "plan", "--source", str(source), PROJECT_FLAG, PROJECT_NAME,
"--org", TEST_ORG, "--elected-on", ELECTION_DATE, "--out", str(plan),
env={"GIT_CONFIG_COUNT": "1", "GIT_CONFIG_KEY_0": "user.name",
"GIT_CONFIG_VALUE_0": DOMAIN_USER})
env=appended_to_command_scope(os.environ,
[("user.name", DOMAIN_USER)]))
assert result.returncode == 0, result.stdout + result.stderr
assert '\nelected_by: "CORP\\\\tom"\n' in text_of(plan)
for path, leg in ANSWERS:
Expand Down
15 changes: 7 additions & 8 deletions tests/test_adopt_reencoded_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@

import pytest

from conftest import (ADOPT, findings, git, make_source_repo, planned,
refused_before_any_leg, run_script)
from conftest import (ADOPT, appended_to_command_scope, findings, git,
make_source_repo, planned, refused_before_any_leg,
run_script)
from test_adopt_nested_attributes import (EMPTY_TREE, GITHUB_ATTRIBUTES,
REENCODED, ROOT, ROOT_ATTRIBUTES,
SOURCE, adopted_by_execute, checked,
Expand Down Expand Up @@ -101,12 +102,10 @@ def raw_plan(base: Path, files: dict, answers: dict) -> Path:

def configure(monkeypatch: pytest.MonkeyPatch, pairs) -> None:
"""Each `(key, value)` of `pairs` in git's command scope, after what
the environment holds, for this process and every git it starts."""
held = int(os.environ.get("GIT_CONFIG_COUNT") or 0)
for n, (key, value) in enumerate(pairs, held):
monkeypatch.setenv(f"GIT_CONFIG_KEY_{n}", key)
monkeypatch.setenv(f"GIT_CONFIG_VALUE_{n}", value)
monkeypatch.setenv("GIT_CONFIG_COUNT", str(held + len(pairs)))
the environment holds, for this process and every git it starts:
appended by `appended_to_command_scope` (#758)."""
for name, value in appended_to_command_scope(os.environ, pairs).items():
monkeypatch.setenv(name, value)


@pytest.fixture(scope="module")
Expand Down
Loading
Loading