fix: network property means any network reach, not only HTTP (#144)
Files changed: - CHANGES.md - VERSION - tools/CONTRACT.md - tools/chemenu/cli_contract.py - tools/chemenu/commands/git_publish.py - tools/chemenu/commands/upstream_cmd.py - tools/chemenu/commands/version_cmd.py - tools/chemenu/tests/test_cli.py - tools/chemenu/version.py
This commit is contained in:
1 parent
16c911fca5
commit
906d63fae2
9 files changed
+86
-24
No files matched your search
+4
-4
@@ -1611,7 +1611,7 @@ Fetch `<remote>/<branch>` and bring the local branch up to date with it.
|
||||
- idempotent: yes
|
||||
- atomic: No - fetch, then at most one merge/rebase attempt, aborted cleanly on failure
|
||||
- budget: counted
|
||||
- network: no
|
||||
- network: yes
|
||||
- gates: rebase-review
|
||||
|
||||
**EXAMPLES**
|
||||
@@ -1664,7 +1664,7 @@ Reconcile with `<remote>/<branch>`, then stage all changes, commit, and push.
|
||||
- idempotent: no
|
||||
- atomic: No - sequential git operations, but every gate runs before staging
|
||||
- budget: counted
|
||||
- network: no
|
||||
- network: yes
|
||||
- gates: mass-update, publish-remote, rebase-review
|
||||
|
||||
**EXAMPLES**
|
||||
@@ -2566,7 +2566,7 @@ Ask the origin's release feed whether a newer stack exists.
|
||||
**NOTES**
|
||||
|
||||
- Asks the release feed for its latest release and compares it with `VERSION`: `state` is `current`, `update`, `migration` (the step crosses a compatibility boundary) or `ahead`.
|
||||
- One of the **two** commands in `wikitool` that make a network call, and the only one whose whole job it is - `version notes` is the other, and only on a distributed instance.
|
||||
- The only command whose whole job is the network call - `version notes` reaches the same feed too, but only as a fallback on a distributed instance.
|
||||
- Never reached implicitly from another command, needs no key, and times out after `--timeout` seconds (default 10).
|
||||
- The feed is `--url`, else `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin. `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously.
|
||||
- For `update` or `migration` it prints that applying the release is a separate, manual step (`INSTALL.md` § "Eine Instanz aktualisieren").
|
||||
@@ -3042,7 +3042,7 @@ Take a stack update into a private instance's branch, machinery only.
|
||||
- idempotent: no
|
||||
- atomic: **No** - can leave an open, uncommitted merge behind on refusal after fetching
|
||||
- budget: counted
|
||||
- network: no
|
||||
- network: yes
|
||||
|
||||
**EXAMPLES**
|
||||
|
||||
|
||||
@@ -51,6 +51,15 @@ class Budget(str, Enum):
|
||||
|
||||
|
||||
class Network(str, Enum):
|
||||
"""Whether at least one path through this command can reach an endpoint outside this
|
||||
checkout - an HTTP call `wikitool` makes itself (release feed, task tracker), or a git
|
||||
operation against a remote (`fetch`, `ls-remote`, `push`). `YES` if either kind is
|
||||
possible, not only if it is the usual case: a flag that avoids it (`--offline`,
|
||||
`--no-fetch`) or a configuration with no remote endpoint (a markdown tracker, a remote
|
||||
pointed at a local path) does not turn the value back to `NO` - what matters is whether the
|
||||
command can stall or fail on an unreachable network, not what it does on a good day. A git
|
||||
call that only reads refs already on disk (`rev-parse`, `rev-list`, `remote get-url`) is not
|
||||
a network access on its own."""
|
||||
YES = "yes"
|
||||
NO = "no"
|
||||
|
||||
|
||||
@@ -1010,6 +1010,7 @@ def apply_reconcile(outcome: ReconcileOutcome, remote: str, branch: str, command
|
||||
idempotent=cli_contract.Idempotent.YES,
|
||||
atomic="No - fetch, then at most one merge/rebase attempt, aborted cleanly on failure",
|
||||
budget=cli_contract.Budget.COUNTED,
|
||||
network=cli_contract.Network.YES,
|
||||
gates=("rebase-review",),
|
||||
),
|
||||
notes=(
|
||||
@@ -1089,6 +1090,7 @@ def sync_command(
|
||||
idempotent=cli_contract.Idempotent.NO,
|
||||
atomic="No - sequential git operations, but every gate runs before staging",
|
||||
budget=cli_contract.Budget.COUNTED,
|
||||
network=cli_contract.Network.YES,
|
||||
gates=("mass-update", "publish-remote", "rebase-review"),
|
||||
),
|
||||
notes=(
|
||||
|
||||
@@ -249,6 +249,7 @@ def _merge_success_message(
|
||||
idempotent=cli_contract.Idempotent.NO,
|
||||
atomic="**No** - can leave an open, uncommitted merge behind on refusal after fetching",
|
||||
budget=cli_contract.Budget.COUNTED,
|
||||
network=cli_contract.Network.YES,
|
||||
),
|
||||
notes=(
|
||||
"Refuses on a dirty working tree, a merge already in progress, or a remote that does "
|
||||
|
||||
@@ -24,11 +24,11 @@ number means, and `instructions/dev/version-parts.md` for the candidate model):
|
||||
*distributed* instance, whose `CHANGES.md` is a stub `dist upgrade` never
|
||||
overwrites, it falls back to the release feed, because otherwise the command
|
||||
can never answer there - not today and not after any future release.
|
||||
- `version check` and that fallback are the only two network calls in
|
||||
`wikitool`, and neither is implicit: `check` exists for the call, `notes`
|
||||
announces the URL on stderr before asking and takes `--offline`. Both need
|
||||
no key, both time out, and a feed that cannot be reached is reported as an
|
||||
error rather than silently answered as "up to date" or "no notes".
|
||||
- `version check` and that fallback both reach the release feed, and neither
|
||||
is implicit: `check` exists for the call, `notes` announces the URL on
|
||||
stderr before asking and takes `--offline`. Both need no key, both time
|
||||
out, and a feed that cannot be reached is reported as an error rather than
|
||||
silently answered as "up to date" or "no notes".
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -157,9 +157,8 @@ def show_command(
|
||||
"Asks the release feed for its latest release and compares it with `VERSION`: `state` "
|
||||
"is `current`, `update`, `migration` (the step crosses a compatibility boundary) or "
|
||||
"`ahead`.",
|
||||
"One of the **two** commands in `wikitool` that make a network call, and the only one "
|
||||
"whose whole job it is - `version notes` is the other, and only on a distributed "
|
||||
"instance.",
|
||||
"The only command whose whole job is the network call - `version notes` reaches the "
|
||||
"same feed too, but only as a fallback on a distributed instance.",
|
||||
"Never reached implicitly from another command, needs no key, and times out after "
|
||||
"`--timeout` seconds (default 10).",
|
||||
"The feed is `--url`, else `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the "
|
||||
@@ -205,9 +204,10 @@ def check_command(
|
||||
):
|
||||
"""Ask the origin's release feed whether a newer stack exists.
|
||||
|
||||
The only networked command in `wikitool`. Exits 1 if the feed cannot be
|
||||
reached or does not answer with a release - an unreachable feed is not the
|
||||
same answer as "up to date", and must never be reported as one."""
|
||||
The only command whose whole job is the network call. Exits 1 if the feed
|
||||
cannot be reached or does not answer with a release - an unreachable feed
|
||||
is not the same answer as "up to date", and must never be reported as
|
||||
one."""
|
||||
import os
|
||||
|
||||
try:
|
||||
|
||||
@@ -285,6 +285,32 @@ def test_every_gated_record_shows_its_re_run_after_exit_42():
|
||||
assert missing == []
|
||||
|
||||
|
||||
def test_network_yes_is_exactly_the_commands_that_can_reach_outside_this_checkout():
|
||||
"""Gitea #144: `network:` means *any* reach outside this checkout - an HTTP call
|
||||
`wikitool` makes itself, or a git operation against a remote (fetch/ls-remote/push) -
|
||||
not only the two `version_cmd.py` used to claim exclusivity for. Pinned as an explicit
|
||||
set so a command gaining or losing that reach is a deliberate edit here, not a silent
|
||||
drift between the property and what the command actually does."""
|
||||
expected = {
|
||||
"sync",
|
||||
"publish",
|
||||
"upstream merge",
|
||||
"version check",
|
||||
"version notes",
|
||||
"review",
|
||||
"task new",
|
||||
"task list",
|
||||
"task close",
|
||||
"doctor",
|
||||
}
|
||||
actual = {
|
||||
path
|
||||
for path, rec in cli_contract.all_records().items()
|
||||
if rec.properties.network is cli_contract.Network.YES
|
||||
}
|
||||
assert actual == expected
|
||||
|
||||
|
||||
# --- fail()'s ON FAILURE hint, through two real commands (Gitea #143) ---
|
||||
|
||||
|
||||
|
||||
@@ -348,13 +348,13 @@ def fetch_latest(
|
||||
"""The version the release feed reports as latest.
|
||||
|
||||
The network call sits behind `fetcher` so every caller above this line -
|
||||
and every test - can run without a network. This is the one place in
|
||||
`wikitool` that talks to a remote host, and only two commands reach it:
|
||||
`version check`, whose whole job it is, and `version notes` on a
|
||||
*distributed* instance, whose local `CHANGES.md` is a stub with no entry to
|
||||
print (see `fetch_latest_notes`). Neither is implicit - `check` exists for
|
||||
the call, and `notes` announces the URL it is asking before it asks, on
|
||||
stderr, and takes `--offline` for a caller that wants none of it.
|
||||
and every test - can run without a network. This is the one place that
|
||||
talks to the **release feed**, and only two commands reach it: `version
|
||||
check`, whose whole job it is, and `version notes` on a *distributed*
|
||||
instance, whose local `CHANGES.md` is a stub with no entry to print (see
|
||||
`fetch_latest_notes`). Neither is implicit - `check` exists for the call,
|
||||
and `notes` announces the URL it is asking before it asks, on stderr, and
|
||||
takes `--offline` for a caller that wants none of it.
|
||||
"""
|
||||
fetch = fetcher or _urlopen_fetch
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user