arthexis 0.1.15__py3-none-any.whl → 0.1.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/METADATA +1 -2
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/RECORD +40 -39
- config/settings.py +3 -0
- config/urls.py +5 -0
- core/admin.py +242 -15
- core/admindocs.py +44 -3
- core/apps.py +1 -1
- core/backends.py +46 -8
- core/changelog.py +66 -5
- core/github_issues.py +12 -7
- core/mailer.py +9 -5
- core/models.py +121 -29
- core/release.py +107 -2
- core/system.py +209 -2
- core/tasks.py +5 -7
- core/test_system_info.py +16 -0
- core/tests.py +329 -0
- core/views.py +279 -40
- nodes/admin.py +25 -1
- nodes/models.py +70 -4
- nodes/rfid_sync.py +15 -0
- nodes/tests.py +119 -0
- nodes/utils.py +3 -0
- ocpp/admin.py +92 -10
- ocpp/consumers.py +38 -0
- ocpp/models.py +19 -4
- ocpp/tasks.py +156 -2
- ocpp/test_rfid.py +92 -5
- ocpp/tests.py +243 -1
- ocpp/views.py +23 -5
- pages/admin.py +126 -4
- pages/context_processors.py +20 -1
- pages/models.py +3 -1
- pages/module_defaults.py +156 -0
- pages/tests.py +241 -8
- pages/urls.py +1 -0
- pages/views.py +61 -4
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/WHEEL +0 -0
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/top_level.txt +0 -0
core/release.py
CHANGED
|
@@ -114,6 +114,21 @@ class ReleaseError(Exception):
|
|
|
114
114
|
pass
|
|
115
115
|
|
|
116
116
|
|
|
117
|
+
class PostPublishWarning(ReleaseError):
|
|
118
|
+
"""Raised when distribution uploads succeed but post-publish tasks need attention."""
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
message: str,
|
|
123
|
+
*,
|
|
124
|
+
uploaded: Sequence[str],
|
|
125
|
+
followups: Optional[Sequence[str]] = None,
|
|
126
|
+
) -> None:
|
|
127
|
+
super().__init__(message)
|
|
128
|
+
self.uploaded = list(uploaded)
|
|
129
|
+
self.followups = list(followups or [])
|
|
130
|
+
|
|
131
|
+
|
|
117
132
|
class TestsFailed(ReleaseError):
|
|
118
133
|
"""Raised when the test suite fails.
|
|
119
134
|
|
|
@@ -303,6 +318,47 @@ def _git_remote_url(remote: str = "origin") -> Optional[str]:
|
|
|
303
318
|
return (proc.stdout or "").strip() or None
|
|
304
319
|
|
|
305
320
|
|
|
321
|
+
def _git_tag_commit(tag_name: str) -> Optional[str]:
|
|
322
|
+
"""Return the commit referenced by ``tag_name`` in the local repository."""
|
|
323
|
+
|
|
324
|
+
for ref in (f"{tag_name}^{{}}", tag_name):
|
|
325
|
+
proc = subprocess.run(
|
|
326
|
+
["git", "rev-parse", ref],
|
|
327
|
+
capture_output=True,
|
|
328
|
+
text=True,
|
|
329
|
+
check=False,
|
|
330
|
+
)
|
|
331
|
+
if proc.returncode == 0:
|
|
332
|
+
commit = (proc.stdout or "").strip()
|
|
333
|
+
if commit:
|
|
334
|
+
return commit
|
|
335
|
+
return None
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _git_remote_tag_commit(remote: str, tag_name: str) -> Optional[str]:
|
|
339
|
+
"""Return the commit referenced by ``tag_name`` on ``remote`` if it exists."""
|
|
340
|
+
|
|
341
|
+
proc = subprocess.run(
|
|
342
|
+
["git", "ls-remote", "--tags", remote, tag_name],
|
|
343
|
+
capture_output=True,
|
|
344
|
+
text=True,
|
|
345
|
+
check=False,
|
|
346
|
+
)
|
|
347
|
+
if proc.returncode != 0:
|
|
348
|
+
return None
|
|
349
|
+
|
|
350
|
+
commit = None
|
|
351
|
+
for line in (proc.stdout or "").splitlines():
|
|
352
|
+
parts = line.strip().split()
|
|
353
|
+
if len(parts) != 2:
|
|
354
|
+
continue
|
|
355
|
+
sha, ref = parts
|
|
356
|
+
commit = sha
|
|
357
|
+
if ref.endswith("^{}"):
|
|
358
|
+
return sha
|
|
359
|
+
return commit
|
|
360
|
+
|
|
361
|
+
|
|
306
362
|
def _remote_with_credentials(url: str, creds: GitCredentials) -> Optional[str]:
|
|
307
363
|
if not creds.has_auth():
|
|
308
364
|
return None
|
|
@@ -335,6 +391,17 @@ def _push_tag(tag_name: str, package: Package) -> None:
|
|
|
335
391
|
_run(["git", "push", "origin", tag_name])
|
|
336
392
|
return
|
|
337
393
|
except subprocess.CalledProcessError as exc:
|
|
394
|
+
remote_commit = _git_remote_tag_commit("origin", tag_name)
|
|
395
|
+
local_commit = _git_tag_commit(tag_name)
|
|
396
|
+
if remote_commit:
|
|
397
|
+
if local_commit and remote_commit == local_commit:
|
|
398
|
+
# Another process already pushed the tag; treat as success.
|
|
399
|
+
return
|
|
400
|
+
message = (
|
|
401
|
+
"Git rejected tag {tag} because it already exists on the remote. "
|
|
402
|
+
"Delete the remote tag or choose a new version before retrying."
|
|
403
|
+
).format(tag=tag_name)
|
|
404
|
+
raise ReleaseError(message) from exc
|
|
338
405
|
if not _git_authentication_missing(exc):
|
|
339
406
|
raise
|
|
340
407
|
auth_error = exc
|
|
@@ -659,8 +726,46 @@ def publish(
|
|
|
659
726
|
uploaded.append(target.name)
|
|
660
727
|
|
|
661
728
|
tag_name = f"v{version}"
|
|
662
|
-
|
|
663
|
-
|
|
729
|
+
try:
|
|
730
|
+
_run(["git", "tag", tag_name])
|
|
731
|
+
except subprocess.CalledProcessError as exc:
|
|
732
|
+
details = _format_subprocess_error(exc)
|
|
733
|
+
if uploaded:
|
|
734
|
+
uploads = ", ".join(uploaded)
|
|
735
|
+
if details:
|
|
736
|
+
message = (
|
|
737
|
+
f"Upload to {uploads} completed, but creating git tag {tag_name} failed: {details}"
|
|
738
|
+
)
|
|
739
|
+
else:
|
|
740
|
+
message = (
|
|
741
|
+
f"Upload to {uploads} completed, but creating git tag {tag_name} failed."
|
|
742
|
+
)
|
|
743
|
+
followups = [f"Create and push git tag {tag_name} manually once the repository is ready."]
|
|
744
|
+
raise PostPublishWarning(
|
|
745
|
+
message,
|
|
746
|
+
uploaded=uploaded,
|
|
747
|
+
followups=followups,
|
|
748
|
+
) from exc
|
|
749
|
+
raise ReleaseError(
|
|
750
|
+
f"Failed to create git tag {tag_name}: {details or exc}"
|
|
751
|
+
) from exc
|
|
752
|
+
|
|
753
|
+
try:
|
|
754
|
+
_push_tag(tag_name, package)
|
|
755
|
+
except ReleaseError as exc:
|
|
756
|
+
if uploaded:
|
|
757
|
+
uploads = ", ".join(uploaded)
|
|
758
|
+
message = f"Upload to {uploads} completed, but {exc}"
|
|
759
|
+
followups = [
|
|
760
|
+
f"Push git tag {tag_name} to origin after resolving the reported issue."
|
|
761
|
+
]
|
|
762
|
+
warning = PostPublishWarning(
|
|
763
|
+
message,
|
|
764
|
+
uploaded=uploaded,
|
|
765
|
+
followups=followups,
|
|
766
|
+
)
|
|
767
|
+
raise warning from exc
|
|
768
|
+
raise
|
|
664
769
|
return uploaded
|
|
665
770
|
|
|
666
771
|
|
core/system.py
CHANGED
|
@@ -20,10 +20,18 @@ from django.http import HttpResponseRedirect
|
|
|
20
20
|
from django.urls import path, reverse
|
|
21
21
|
from django.utils import timezone
|
|
22
22
|
from django.utils.formats import date_format
|
|
23
|
+
from django.utils.html import format_html, format_html_join
|
|
23
24
|
from django.utils.translation import gettext_lazy as _, ngettext
|
|
24
25
|
|
|
25
26
|
from core.auto_upgrade import AUTO_UPGRADE_TASK_NAME, AUTO_UPGRADE_TASK_PATH
|
|
26
27
|
from core import changelog as changelog_utils
|
|
28
|
+
from core.release import (
|
|
29
|
+
_git_authentication_missing,
|
|
30
|
+
_git_remote_url,
|
|
31
|
+
_manager_git_credentials,
|
|
32
|
+
_remote_with_credentials,
|
|
33
|
+
)
|
|
34
|
+
from core.tasks import check_github_updates
|
|
27
35
|
from utils import revision
|
|
28
36
|
|
|
29
37
|
|
|
@@ -163,7 +171,7 @@ def _regenerate_changelog() -> None:
|
|
|
163
171
|
previous_text = (
|
|
164
172
|
changelog_path.read_text(encoding="utf-8") if changelog_path.exists() else None
|
|
165
173
|
)
|
|
166
|
-
range_spec = changelog_utils.determine_range_spec()
|
|
174
|
+
range_spec = changelog_utils.determine_range_spec(previous_text=previous_text)
|
|
167
175
|
sections = changelog_utils.collect_sections(
|
|
168
176
|
range_spec=range_spec, previous_text=previous_text
|
|
169
177
|
)
|
|
@@ -173,6 +181,120 @@ def _regenerate_changelog() -> None:
|
|
|
173
181
|
changelog_path.write_text(content, encoding="utf-8")
|
|
174
182
|
|
|
175
183
|
|
|
184
|
+
def _format_git_command_output(
|
|
185
|
+
command: list[str], result: subprocess.CompletedProcess[str]
|
|
186
|
+
) -> str:
|
|
187
|
+
"""Return a readable summary of a git command execution."""
|
|
188
|
+
|
|
189
|
+
command_display = "$ " + " ".join(command)
|
|
190
|
+
message_parts = []
|
|
191
|
+
if result.stdout:
|
|
192
|
+
message_parts.append(result.stdout.strip())
|
|
193
|
+
if result.stderr:
|
|
194
|
+
message_parts.append(result.stderr.strip())
|
|
195
|
+
if result.returncode != 0:
|
|
196
|
+
message_parts.append(f"[exit status {result.returncode}]")
|
|
197
|
+
if message_parts:
|
|
198
|
+
return command_display + "\n" + "\n".join(part for part in message_parts if part)
|
|
199
|
+
return command_display
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _git_status() -> str:
|
|
203
|
+
"""Return the repository status after attempting to commit."""
|
|
204
|
+
|
|
205
|
+
status_result = subprocess.run(
|
|
206
|
+
["git", "status", "--short", "--branch"],
|
|
207
|
+
capture_output=True,
|
|
208
|
+
text=True,
|
|
209
|
+
check=False,
|
|
210
|
+
)
|
|
211
|
+
stdout = status_result.stdout.strip()
|
|
212
|
+
stderr = status_result.stderr.strip()
|
|
213
|
+
if stdout and stderr:
|
|
214
|
+
return stdout + "\n" + stderr
|
|
215
|
+
return stdout or stderr
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _commit_changelog() -> tuple[bool, str, str]:
|
|
219
|
+
"""Stage, commit, and push the changelog file."""
|
|
220
|
+
|
|
221
|
+
def _retry_push_with_release_credentials(
|
|
222
|
+
command: list[str],
|
|
223
|
+
result: subprocess.CompletedProcess[str],
|
|
224
|
+
) -> bool:
|
|
225
|
+
exc = subprocess.CalledProcessError(
|
|
226
|
+
result.returncode,
|
|
227
|
+
command,
|
|
228
|
+
output=result.stdout,
|
|
229
|
+
stderr=result.stderr,
|
|
230
|
+
)
|
|
231
|
+
if not _git_authentication_missing(exc):
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
creds = _manager_git_credentials()
|
|
235
|
+
if not creds or not creds.has_auth():
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
remote_url = _git_remote_url("origin")
|
|
239
|
+
if not remote_url:
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
authed_url = _remote_with_credentials(remote_url, creds)
|
|
243
|
+
if not authed_url:
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
retry_command = ["git", "push", authed_url]
|
|
247
|
+
retry_result = subprocess.run(
|
|
248
|
+
retry_command,
|
|
249
|
+
capture_output=True,
|
|
250
|
+
text=True,
|
|
251
|
+
check=False,
|
|
252
|
+
)
|
|
253
|
+
formatted_retry = _format_git_command_output(retry_command, retry_result)
|
|
254
|
+
if formatted_retry:
|
|
255
|
+
outputs.append(formatted_retry)
|
|
256
|
+
logger.info(
|
|
257
|
+
"Executed %s with exit code %s",
|
|
258
|
+
retry_command,
|
|
259
|
+
retry_result.returncode,
|
|
260
|
+
)
|
|
261
|
+
return retry_result.returncode == 0
|
|
262
|
+
|
|
263
|
+
git_commands: list[list[str]] = [
|
|
264
|
+
["git", "add", "CHANGELOG.rst"],
|
|
265
|
+
[
|
|
266
|
+
"git",
|
|
267
|
+
"commit",
|
|
268
|
+
"-m",
|
|
269
|
+
"chore: update changelog",
|
|
270
|
+
"--",
|
|
271
|
+
"CHANGELOG.rst",
|
|
272
|
+
],
|
|
273
|
+
["git", "push"],
|
|
274
|
+
]
|
|
275
|
+
outputs: list[str] = []
|
|
276
|
+
success = True
|
|
277
|
+
|
|
278
|
+
for command in git_commands:
|
|
279
|
+
result = subprocess.run(
|
|
280
|
+
command, capture_output=True, text=True, check=False
|
|
281
|
+
)
|
|
282
|
+
formatted = _format_git_command_output(command, result)
|
|
283
|
+
outputs.append(formatted)
|
|
284
|
+
logger.info("Executed %s with exit code %s", command, result.returncode)
|
|
285
|
+
if result.returncode != 0:
|
|
286
|
+
if command[:2] == ["git", "push"] and _retry_push_with_release_credentials(
|
|
287
|
+
command, result
|
|
288
|
+
):
|
|
289
|
+
continue
|
|
290
|
+
success = False
|
|
291
|
+
break
|
|
292
|
+
|
|
293
|
+
command_output = "\n\n".join(output for output in outputs if output)
|
|
294
|
+
repo_status = _git_status()
|
|
295
|
+
return success, command_output, repo_status
|
|
296
|
+
|
|
297
|
+
|
|
176
298
|
@dataclass(frozen=True)
|
|
177
299
|
class SystemField:
|
|
178
300
|
"""Metadata describing a single entry on the system admin page."""
|
|
@@ -716,7 +838,14 @@ def _gather_info() -> dict:
|
|
|
716
838
|
info["service"] = service_file.read_text().strip() if service_file.exists() else ""
|
|
717
839
|
|
|
718
840
|
mode_file = lock_dir / "nginx_mode.lck"
|
|
719
|
-
|
|
841
|
+
if mode_file.exists():
|
|
842
|
+
try:
|
|
843
|
+
raw_mode = mode_file.read_text().strip()
|
|
844
|
+
except OSError:
|
|
845
|
+
raw_mode = ""
|
|
846
|
+
else:
|
|
847
|
+
raw_mode = ""
|
|
848
|
+
mode = raw_mode.lower() or "internal"
|
|
720
849
|
info["mode"] = mode
|
|
721
850
|
default_port = 8000 if mode == "public" else 8888
|
|
722
851
|
detected_port: int | None = None
|
|
@@ -882,6 +1011,36 @@ def _system_changelog_report_view(request):
|
|
|
882
1011
|
request,
|
|
883
1012
|
_("Select at least one changelog entry to exclude."),
|
|
884
1013
|
)
|
|
1014
|
+
elif action == "commit":
|
|
1015
|
+
success, command_output, repo_status = _commit_changelog()
|
|
1016
|
+
details: list[str] = []
|
|
1017
|
+
if command_output:
|
|
1018
|
+
details.append(
|
|
1019
|
+
format_html(
|
|
1020
|
+
"<div class=\"changelog-git-output\"><strong>{}</strong><pre>{}</pre></div>",
|
|
1021
|
+
_("Command log"),
|
|
1022
|
+
command_output,
|
|
1023
|
+
)
|
|
1024
|
+
)
|
|
1025
|
+
if repo_status:
|
|
1026
|
+
details.append(
|
|
1027
|
+
format_html(
|
|
1028
|
+
"<div class=\"changelog-git-status\"><strong>{}</strong><pre>{}</pre></div>",
|
|
1029
|
+
_("Repository status"),
|
|
1030
|
+
repo_status,
|
|
1031
|
+
)
|
|
1032
|
+
)
|
|
1033
|
+
details_html = (
|
|
1034
|
+
format_html_join("", "{}", ((detail,) for detail in details))
|
|
1035
|
+
if details
|
|
1036
|
+
else ""
|
|
1037
|
+
)
|
|
1038
|
+
if success:
|
|
1039
|
+
base_message = _("Committed the changelog and pushed to the current branch.")
|
|
1040
|
+
messages.success(request, format_html("{}{}", base_message, details_html))
|
|
1041
|
+
else:
|
|
1042
|
+
base_message = _("Unable to commit the changelog.")
|
|
1043
|
+
messages.error(request, format_html("{}{}", base_message, details_html))
|
|
885
1044
|
else:
|
|
886
1045
|
try:
|
|
887
1046
|
_regenerate_changelog()
|
|
@@ -927,6 +1086,49 @@ def _system_upgrade_report_view(request):
|
|
|
927
1086
|
return TemplateResponse(request, "admin/system_upgrade_report.html", context)
|
|
928
1087
|
|
|
929
1088
|
|
|
1089
|
+
def _trigger_upgrade_check() -> bool:
|
|
1090
|
+
"""Return ``True`` when the upgrade check was queued asynchronously."""
|
|
1091
|
+
|
|
1092
|
+
try:
|
|
1093
|
+
check_github_updates.delay()
|
|
1094
|
+
except Exception:
|
|
1095
|
+
logger.exception("Failed to enqueue upgrade check; running synchronously instead")
|
|
1096
|
+
check_github_updates()
|
|
1097
|
+
return False
|
|
1098
|
+
return True
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def _system_trigger_upgrade_check_view(request):
|
|
1102
|
+
if request.method != "POST":
|
|
1103
|
+
return HttpResponseRedirect(reverse("admin:system-upgrade-report"))
|
|
1104
|
+
|
|
1105
|
+
try:
|
|
1106
|
+
queued = _trigger_upgrade_check()
|
|
1107
|
+
except Exception as exc: # pragma: no cover - unexpected failure
|
|
1108
|
+
logger.exception("Unable to trigger upgrade check")
|
|
1109
|
+
messages.error(
|
|
1110
|
+
request,
|
|
1111
|
+
_("Unable to trigger an upgrade check: %(error)s")
|
|
1112
|
+
% {"error": str(exc)},
|
|
1113
|
+
)
|
|
1114
|
+
else:
|
|
1115
|
+
if queued:
|
|
1116
|
+
messages.success(
|
|
1117
|
+
request,
|
|
1118
|
+
_("Upgrade check requested. The task will run shortly."),
|
|
1119
|
+
)
|
|
1120
|
+
else:
|
|
1121
|
+
messages.success(
|
|
1122
|
+
request,
|
|
1123
|
+
_(
|
|
1124
|
+
"Upgrade check started locally. Review the auto-upgrade log for"
|
|
1125
|
+
" progress."
|
|
1126
|
+
),
|
|
1127
|
+
)
|
|
1128
|
+
|
|
1129
|
+
return HttpResponseRedirect(reverse("admin:system-upgrade-report"))
|
|
1130
|
+
|
|
1131
|
+
|
|
930
1132
|
def patch_admin_system_view() -> None:
|
|
931
1133
|
"""Add custom admin view for system information."""
|
|
932
1134
|
original_get_urls = admin.site.get_urls
|
|
@@ -945,6 +1147,11 @@ def patch_admin_system_view() -> None:
|
|
|
945
1147
|
admin.site.admin_view(_system_upgrade_report_view),
|
|
946
1148
|
name="system-upgrade-report",
|
|
947
1149
|
),
|
|
1150
|
+
path(
|
|
1151
|
+
"system/upgrade-report/run-check/",
|
|
1152
|
+
admin.site.admin_view(_system_trigger_upgrade_check_view),
|
|
1153
|
+
name="system-upgrade-run-check",
|
|
1154
|
+
),
|
|
948
1155
|
]
|
|
949
1156
|
return custom + urls
|
|
950
1157
|
|
core/tasks.py
CHANGED
|
@@ -132,11 +132,15 @@ def check_github_updates() -> None:
|
|
|
132
132
|
mode = "version"
|
|
133
133
|
if mode_file.exists():
|
|
134
134
|
try:
|
|
135
|
-
|
|
135
|
+
raw_mode = mode_file.read_text().strip()
|
|
136
136
|
except (OSError, UnicodeDecodeError):
|
|
137
137
|
logger.warning(
|
|
138
138
|
"Failed to read auto-upgrade mode lockfile", exc_info=True
|
|
139
139
|
)
|
|
140
|
+
else:
|
|
141
|
+
cleaned_mode = raw_mode.lower()
|
|
142
|
+
if cleaned_mode:
|
|
143
|
+
mode = cleaned_mode
|
|
140
144
|
|
|
141
145
|
branch = "main"
|
|
142
146
|
subprocess.run(["git", "fetch", "origin", branch], cwd=base_dir, check=True)
|
|
@@ -226,12 +230,6 @@ def check_github_updates() -> None:
|
|
|
226
230
|
|
|
227
231
|
subprocess.run(args, cwd=base_dir, check=True)
|
|
228
232
|
|
|
229
|
-
if shutil.which("gway"):
|
|
230
|
-
try:
|
|
231
|
-
subprocess.run(["gway", "upgrade"], check=True)
|
|
232
|
-
except subprocess.CalledProcessError:
|
|
233
|
-
logger.warning("gway upgrade failed; continuing anyway", exc_info=True)
|
|
234
|
-
|
|
235
233
|
service_file = base_dir / "locks/service.lck"
|
|
236
234
|
if service_file.exists():
|
|
237
235
|
service = service_file.read_text().strip()
|
core/test_system_info.py
CHANGED
|
@@ -55,6 +55,22 @@ class SystemInfoScreenModeTests(SimpleTestCase):
|
|
|
55
55
|
lock_dir.rmdir()
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
class SystemInfoModeTests(SimpleTestCase):
|
|
59
|
+
def test_public_mode_case_insensitive(self):
|
|
60
|
+
lock_dir = Path(settings.BASE_DIR) / "locks"
|
|
61
|
+
lock_dir.mkdir(exist_ok=True)
|
|
62
|
+
lock_file = lock_dir / "nginx_mode.lck"
|
|
63
|
+
lock_file.write_text("PUBLIC", encoding="utf-8")
|
|
64
|
+
try:
|
|
65
|
+
info = _gather_info()
|
|
66
|
+
self.assertEqual(info["mode"], "public")
|
|
67
|
+
self.assertEqual(info["port"], 8000)
|
|
68
|
+
finally:
|
|
69
|
+
lock_file.unlink()
|
|
70
|
+
if not any(lock_dir.iterdir()):
|
|
71
|
+
lock_dir.rmdir()
|
|
72
|
+
|
|
73
|
+
|
|
58
74
|
class SystemInfoRevisionTests(SimpleTestCase):
|
|
59
75
|
@patch("core.system.revision.get_revision", return_value="abcdef1234567890")
|
|
60
76
|
def test_includes_full_revision(self, mock_revision):
|