fix(#4085): align dirty display probes
This commit is contained in:
1 parent
5f8fd9d85a
commit
678a1ee926
2 files changed
+56
-21
No files matched your search
+14
-21
@@ -431,21 +431,15 @@ def _dirty_suffix(path: Path, timeout=1) -> str:
|
||||
out, ok = _run_git(['diff-index', '--quiet', 'HEAD', '--'], path, timeout=timeout)
|
||||
if ok:
|
||||
return ""
|
||||
# diff-index --quiet exits 1 with no stdout/stderr to *signal* a dirty tree
|
||||
# (not an error). _run_git() substitutes a synthetic "git exited with
|
||||
# status N" diagnostic when both streams are empty, which makes the naive
|
||||
# `if not out` guard always false on dirty trees — silently dropping the
|
||||
# suffix and defeating dev-build cache busting (static/foo.js?v=… stays
|
||||
# identical to the last-committed version). Treat the synthetic shape as
|
||||
# the dirty signal; real errors (timeouts, missing git) carry a different
|
||||
# diagnostic and correctly suppress the suffix.
|
||||
if not out or out.startswith('git exited with status '):
|
||||
diff, diff_ok = _run_git(['diff', '--binary', 'HEAD', '--'], path, timeout=timeout)
|
||||
if diff_ok and diff:
|
||||
digest = hashlib.sha1(diff.encode('utf-8', errors='replace')).hexdigest()[:8]
|
||||
return f"-dirty-{digest}"
|
||||
return "-dirty"
|
||||
return ""
|
||||
# Only diff-index status 1 means dirty. Keep version display consistent
|
||||
# with the strict action-time probe; all other failures suppress the suffix.
|
||||
if out != 'git exited with status 1':
|
||||
return ""
|
||||
diff, diff_ok = _run_git(['diff', '--binary', 'HEAD', '--'], path, timeout=timeout)
|
||||
if diff_ok and diff:
|
||||
digest = hashlib.sha1(diff.encode('utf-8', errors='replace')).hexdigest()[:8]
|
||||
return f"-dirty-{digest}"
|
||||
return "-dirty"
|
||||
|
||||
|
||||
def _describe_git_version(path: Path, *, timeout=5, dirty_timeout=1) -> str | None:
|
||||
@@ -1943,16 +1937,15 @@ def _discard_local_changes(path: Path, reset_ref: str) -> bool:
|
||||
|
||||
|
||||
def apply_force_update(target: str, channel=None) -> dict:
|
||||
"""Force-reset the target repo to the latest remote HEAD.
|
||||
"""Discard local changes for the requested update target.
|
||||
|
||||
Unlike apply_update() which requires a clean working tree and refuses
|
||||
merge conflicts, this discards all local modifications (checkout .) and
|
||||
resets to origin/<branch> — equivalent to what the diverged/conflict
|
||||
error messages ask the user to run manually.
|
||||
resets to the selected update ref. A dirty stable WebUI checkout with no
|
||||
promoted ref resets to its symbolic HEAD so the commit itself is unchanged.
|
||||
|
||||
Should only be called when apply_update() has already returned a
|
||||
response with ``conflict: True`` or ``diverged: True`` and the user
|
||||
has confirmed they want to discard local changes.
|
||||
The endpoint is called after the user has confirmed they want to discard
|
||||
local changes, including the stable no-ref dirty-checkout recovery path.
|
||||
|
||||
CHANNEL SAFETY (rewind guard): ``reset --hard`` is destructive. When the
|
||||
selected channel resolves to a ref that is an ANCESTOR of HEAD (i.e. the
|
||||
|
||||
@@ -813,6 +813,48 @@ def test_run_git_handles_missing_stdout_after_decode_thread_failure(tmp_path):
|
||||
assert out == ''
|
||||
|
||||
|
||||
@pytest.mark.parametrize('probe_output', [
|
||||
'git exited with status 2',
|
||||
'git exited with status 128',
|
||||
'git exited with status -9',
|
||||
])
|
||||
def test_describe_git_version_suppresses_unknown_dirty_probe_status(
|
||||
tmp_path, monkeypatch, probe_output,
|
||||
):
|
||||
calls = []
|
||||
|
||||
def fake_git(args, cwd, timeout=10):
|
||||
calls.append(args)
|
||||
if args == ['describe', '--tags', '--always']:
|
||||
return 'v0.52.5', True
|
||||
if args == ['diff-index', '--quiet', 'HEAD', '--']:
|
||||
return probe_output, False
|
||||
raise AssertionError(f'unexpected git args: {args!r}')
|
||||
|
||||
monkeypatch.setattr(updates, '_run_git', fake_git)
|
||||
|
||||
assert updates._describe_git_version(tmp_path) == 'v0.52.5'
|
||||
assert calls == [
|
||||
['describe', '--tags', '--always'],
|
||||
['diff-index', '--quiet', 'HEAD', '--'],
|
||||
]
|
||||
|
||||
|
||||
def test_describe_git_version_marks_exact_dirty_probe_status(tmp_path, monkeypatch):
|
||||
def fake_git(args, cwd, timeout=10):
|
||||
if args == ['describe', '--tags', '--always']:
|
||||
return 'v0.52.5', True
|
||||
if args == ['diff-index', '--quiet', 'HEAD', '--']:
|
||||
return 'git exited with status 1', False
|
||||
if args == ['diff', '--binary', 'HEAD', '--']:
|
||||
return 'diff --git a/tracked.txt b/tracked.txt', True
|
||||
raise AssertionError(f'unexpected git args: {args!r}')
|
||||
|
||||
monkeypatch.setattr(updates, '_run_git', fake_git)
|
||||
|
||||
assert updates._describe_git_version(tmp_path).startswith('v0.52.5-dirty-')
|
||||
|
||||
|
||||
def test_split_remote_ref_splits_tracking_ref():
|
||||
"""_split_remote_ref should correctly split origin/branch."""
|
||||
assert updates._split_remote_ref('origin/master') == ('origin', 'master')
|
||||
|
||||
Reference in new issue
Block a user