tests.test_pr module

Tests for repomatic.github.pr.

tests.test_pr.BRANCH = 'sync-fruit-basket'

Arbitrary head branch the sync tests target.

tests.test_pr.BASE_SHA = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

Stand-in SHA for the base branch tip.

tests.test_pr.CANDIDATE_SHA = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'

Stand-in SHA for the commit built from the working tree.

tests.test_pr.REMOTE_SHA = 'cccccccccccccccccccccccccccccccccccccccc'

Stand-in SHA for the tip of an already-published head branch.

tests.test_pr.test_list_open_prs_by_branch_filters_arguments()[source]
tests.test_pr.test_list_open_prs_by_branch_empty()[source]
tests.test_pr.test_close_pr_default_deletes_branch()[source]
tests.test_pr.test_close_pr_can_keep_branch()[source]
tests.test_pr.test_close_pr_unlocks_a_locked_conversation()[source]

A hand-locked PR is unlocked so the retire path’s close comment lands.

tests.test_pr.test_close_open_prs_on_branch_no_match_is_noop()[source]
tests.test_pr.test_close_open_prs_on_branch_closes_every_match()[source]
tests.test_pr.test_needs_push(candidate_tree, remote_tree, remote_commits, expected_commits, expected)[source]
tests.test_pr.git(monkeypatch)[source]

A stand-in for the git layer, wired to the ordinary happy path.

Each test overrides only the calls its own scenario turns on, which keeps the interesting difference visible instead of buried in a stack of patches.

tests.test_pr.gh(monkeypatch)[source]

Capture gh invocations, returning whatever the test queues up.

One stub covers both dispatch points: the module’s own calls and the close path, which routes through the issue module’s lock-recovery wrapper. A single mock keeps each test’s call sequence in one list.

tests.test_pr.verbs(gh_stub)[source]

The gh <noun> <verb> pairs a test’s run produced, in order.

Return type:

list[str]

tests.test_pr.test_upsert_pr_requires_a_base_on_detached_head(git, gh)[source]
tests.test_pr.test_upsert_pr_rejects_a_base_missing_from_the_remote(git, gh)[source]
tests.test_pr.test_upsert_pr_without_changes_or_branch_does_nothing(git, gh)[source]

The quietest path: nothing to publish and nothing to retire.

tests.test_pr.test_upsert_pr_retires_branch_and_pr_when_changes_evaporate(git, gh)[source]

The path a skipped action step could never reach.

tests.test_pr.test_upsert_pr_deletes_an_orphan_branch_with_no_open_pr(git, gh)[source]
tests.test_pr.test_upsert_pr_creates_branch_and_pr(git, gh)[source]
tests.test_pr.test_upsert_pr_updates_an_existing_pr_and_leases_the_push(git, gh)[source]
tests.test_pr.test_upsert_pr_skips_the_push_when_the_branch_already_matches(git, gh)[source]

The check that keeps an unchanged job from re-triggering every workflow.

tests.test_pr.test_upsert_pr_restores_the_checkout_when_the_push_fails(git, gh)[source]
tests.test_pr.test_upsert_pr_survives_a_refused_label_or_assignee(git, gh)[source]

github-actions[bot] cannot be assigned, and that must not lose the PR.

tests.test_pr.test_upsert_pr_opens_against_an_explicit_base_from_a_detached_head(git, gh)[source]

fix-changelog and bump-version check out a raw SHA, not a branch.

tests.test_pr.test_upsert_pr_carries_commits_the_job_made_itself(git, gh)[source]

prepare-release commits freeze and unfreeze; both must reach the PR.

tests.test_pr.test_upsert_pr_replays_carried_commits_onto_a_moved_base(git, gh)[source]
tests.test_pr.test_upsert_pr_publishes_anyway_when_the_replay_conflicts(git, gh)[source]

A branch on a stale base still opens a usable PR; the next run converges.

tests.test_pr.test_upsert_pr_skips_the_replay_when_history_is_unrelatable(git, gh)[source]

A shallow clone answers neither yes nor no, and must not be rebased blind.

tests.test_pr.test_upsert_pr_creates_a_draft_when_asked(git, gh)[source]
tests.test_pr.test_upsert_pr_puts_a_readied_pr_back_into_draft(git, gh)[source]

draft is re-applied on update, matching the action’s always-true mode.

tests.test_pr.test_upsert_pr_leaves_an_already_draft_pr_alone(git, gh)[source]
tests.test_pr.cli_upsert(monkeypatch)[source]

Capture what the pr-sync command hands to upsert_pr.

tests.test_pr.test_pr_sync_cli_resolves_everything_from_the_template(cli_upsert, monkeypatch)[source]

One flag yields branch, labels, draft, title, body and commit message.

tests.test_pr.test_pr_sync_cli_renders_the_upgrade_template(tmp_path, monkeypatch)[source]

The init --upgrade step outputs reach the pull request title and body.

tests.test_pr.test_pr_sync_cli_reads_draft_from_frontmatter(cli_upsert, monkeypatch)[source]
tests.test_pr.test_pr_sync_cli_falls_back_to_the_event_default_branch(cli_upsert, monkeypatch, tmp_path)[source]

A detached checkout takes its base from the CI event payload.

tests.test_pr.test_pr_sync_cli_explicit_labels_override_frontmatter(cli_upsert, monkeypatch)[source]
tests.test_pr.test_pr_sync_cli_validates_its_inputs(cli_upsert, args, error)[source]
tests.test_pr.test_carry_pr_branch_paths_outcomes(monkeypatch, tip, restored, expected)[source]

Work travels only when the branch exists and carries the named file.

Every other outcome is the first run of a fresh accrual, which must be a silent no-op rather than a failure: the branch is legitimately gone after each merge.

tests.test_pr.test_carry_pr_branch_paths_restores_the_fetched_tip(monkeypatch)[source]

The restore reads the tip just fetched, never the branch name.

A branch name resolves against whatever remote-tracking ref the checkout held before the fetch, which on a CI clone is frequently nothing at all.