Source code
Revision control
Copy as Markdown
Other Tools
# mypy: allow-untyped-defs
import io
from tools.ci import check_for_updated_refs
PUSH_OUTPUT = """To github.com:web-platform-tests/wpt.git
= refs/heads/stable:refs/heads/stable [up to date]
- :refs/heads/deleted [deleted]
+ refs/heads/force:refs/heads/force 7151480...62ee8b6 (forced update)
* refs/heads/new:refs/heads/new [new branch]
* refs/tags/v1.0:refs/tags/v1.0 [new tag]
* refs/review/pr/123:refs/review/pr/123 [new reference]
\x20 refs/heads/main:refs/heads/main 2e0d156..fd86363
\x20 HEAD:refs/heads/feature 49d4a17..5105902
\x20 refs/heads/short-sha:refs/heads/short-sha 9731..e320
\x20 refs/heads/long-sha:refs/heads/long-sha 01e1bec7812eb37679c0b1cb436290a83cbc4694..8ec0c04d22002009e9db16f5e3c5518574907c93
! refs/heads/reject1:refs/heads/reject1 [rejected] (non-fast-forward)
! refs/heads/reject2:refs/heads/reject2 [rejected] (already exists)
! refs/heads/reject3:refs/heads/reject3 [rejected] (fetch first)
! refs/heads/reject4:refs/heads/reject4 [rejected] (needs force)
! refs/heads/reject5:refs/heads/reject5 [rejected] (stale info)
! refs/heads/reject6:refs/heads/reject6 [rejected] (remote ref updated since checkout)
! refs/heads/reject7:refs/heads/reject7 [rejected] (new shallow roots not allowed)
! refs/heads/reject8:refs/heads/reject8 [rejected] (atomic push failed)
! refs/heads/reject9:refs/heads/reject9 [remote rejected] (hook declined)
! refs/heads/reject10:refs/heads/reject10 [remote failure] (timeout)
! refs/heads/reject11:refs/heads/reject11 [no match]
Done
"""
def test_parse_push():
s = io.StringIO(PUSH_OUTPUT)
actual = list(check_for_updated_refs.parse_push(s))
expected = [
{
"flag": "=",
"from_ref": "refs/heads/stable",
"to_ref": "refs/heads/stable",
"summary": "[up to date]",
"reason": None,
},
{
"flag": "-",
"from_ref": "",
"to_ref": "refs/heads/deleted",
"summary": "[deleted]",
"reason": None,
},
{
"flag": "+",
"from_ref": "refs/heads/force",
"to_ref": "refs/heads/force",
"summary": "7151480...62ee8b6",
"reason": "forced update",
},
{
"flag": "*",
"from_ref": "refs/heads/new",
"to_ref": "refs/heads/new",
"summary": "[new branch]",
"reason": None,
},
{
"flag": "*",
"from_ref": "refs/tags/v1.0",
"to_ref": "refs/tags/v1.0",
"summary": "[new tag]",
"reason": None,
},
{
"flag": "*",
"from_ref": "refs/review/pr/123",
"to_ref": "refs/review/pr/123",
"summary": "[new reference]",
"reason": None,
},
{
"flag": " ",
"from_ref": "refs/heads/main",
"to_ref": "refs/heads/main",
"summary": "2e0d156..fd86363",
"reason": None,
},
{
"flag": " ",
"from_ref": "HEAD",
"to_ref": "refs/heads/feature",
"summary": "49d4a17..5105902",
"reason": None,
},
{
"flag": " ",
"from_ref": "refs/heads/short-sha",
"to_ref": "refs/heads/short-sha",
"summary": "9731..e320",
"reason": None,
},
{
"flag": " ",
"from_ref": "refs/heads/long-sha",
"to_ref": "refs/heads/long-sha",
"summary": "01e1bec7812eb37679c0b1cb436290a83cbc4694..8ec0c04d22002009e9db16f5e3c5518574907c93",
"reason": None,
},
{
"flag": "!",
"from_ref": "refs/heads/reject1",
"to_ref": "refs/heads/reject1",
"summary": "[rejected]",
"reason": "non-fast-forward",
},
{
"flag": "!",
"from_ref": "refs/heads/reject2",
"to_ref": "refs/heads/reject2",
"summary": "[rejected]",
"reason": "already exists",
},
{
"flag": "!",
"from_ref": "refs/heads/reject3",
"to_ref": "refs/heads/reject3",
"summary": "[rejected]",
"reason": "fetch first",
},
{
"flag": "!",
"from_ref": "refs/heads/reject4",
"to_ref": "refs/heads/reject4",
"summary": "[rejected]",
"reason": "needs force",
},
{
"flag": "!",
"from_ref": "refs/heads/reject5",
"to_ref": "refs/heads/reject5",
"summary": "[rejected]",
"reason": "stale info",
},
{
"flag": "!",
"from_ref": "refs/heads/reject6",
"to_ref": "refs/heads/reject6",
"summary": "[rejected]",
"reason": "remote ref updated since checkout",
},
{
"flag": "!",
"from_ref": "refs/heads/reject7",
"to_ref": "refs/heads/reject7",
"summary": "[rejected]",
"reason": "new shallow roots not allowed",
},
{
"flag": "!",
"from_ref": "refs/heads/reject8",
"to_ref": "refs/heads/reject8",
"summary": "[rejected]",
"reason": "atomic push failed",
},
{
"flag": "!",
"from_ref": "refs/heads/reject9",
"to_ref": "refs/heads/reject9",
"summary": "[remote rejected]",
"reason": "hook declined",
},
{
"flag": "!",
"from_ref": "refs/heads/reject10",
"to_ref": "refs/heads/reject10",
"summary": "[remote failure]",
"reason": "timeout",
},
{
"flag": "!",
"from_ref": "refs/heads/reject11",
"to_ref": "refs/heads/reject11",
"summary": "[no match]",
"reason": None,
},
]
assert expected == actual
def test_parse_push_malformed_lines():
s = io.StringIO(
"""To github.com:test/repo.git
\x20 refs/heads/good:refs/heads/good be30154..bd80959
malformed line without tabs
another bad line
\x20 refs/heads/good2:refs/heads/good2 ae0f96f..207e07b
Done
"""
)
actual = list(check_for_updated_refs.parse_push(s))
expected = [
{
"flag": " ",
"from_ref": "refs/heads/good",
"to_ref": "refs/heads/good",
"summary": "be30154..bd80959",
"reason": None,
},
{
"flag": " ",
"from_ref": "refs/heads/good2",
"to_ref": "refs/heads/good2",
"summary": "ae0f96f..207e07b",
"reason": None,
},
]
assert expected == actual
def test_process_push():
s = io.StringIO(PUSH_OUTPUT)
actual = check_for_updated_refs.process_push(
s,
[
"refs/heads/stable", # Omitted as it wasn't actually updated.
"refs/heads/deleted",
"refs/heads/force",
"refs/heads/new",
"refs/tags/v1.0",
"refs/review/pr/123",
"refs/heads/main",
"refs/heads/feature",
"refs/heads/reject1", # Omitted as it wasn't actually updated.
"refs/heads/nonexistent", # Omitted as it wasn't actually updated.
],
)
expected = {
"refs/heads/deleted": None,
"refs/heads/force": "62ee8b6",
"refs/heads/new": None,
"refs/tags/v1.0": None,
"refs/review/pr/123": None,
"refs/heads/main": "fd86363",
"refs/heads/feature": "5105902",
}
assert expected == actual