Memory of declined pull requests¶
A team that closes a sync pull request without merging it has said no. touchmark remembers that, and does not propose the same content again. It keeps no state for it: the memory lives in the closed pull requests themselves, in the marker at the end of their description.
Who closed it¶
| Closed without merging, and… | It is | touchmark… |
|---|---|---|
touchmark closed it, or the writer or a known_authors account did |
its own close | remembers nothing |
a bot closed it (a GitHub Bot, an account in automation_accounts), or its base branch is gone |
an automatic close | proposes the same content again after memory.auto_close_cooldown (30 days) |
| anyone else, including an actor the platform does not name | a decline | does not propose the same content again |
Automatic closes in a row with the same content back off: the second waits twice as
long, and the third counts as a decline. Its comment suggests keeping the
engineering-assets label out of the stale bot. Until the cooldown ends, the target is
deferred:cooldown.
What a decline covers¶
The marker records every change the pull request carried as a pair (path, from, mode,
to): the path, its blob in the target before, the mode, and the blob the hub proposed (or
a deletion). A decline covers exactly those pairs.
touchmark does not open a new pull request when everything it wants to change now is covered by the target's declines. It does open one when anything is new:
| Declined | Then | Result |
|---|---|---|
| #7: A created, B created | nothing | declined |
| #7: A created, B created | B was edited in the target (it is local) |
a new pull request with A |
| #7: A created, B created | B added to ignore |
a new pull request with A |
| #7: A created | a comment changed in the opt-in file | declined: the parsed file is the same |
| #7: A created, in a repository the hub subscribed without an opt-in file | an empty opt-in file added | declined: the file is parsed the same as the empty one assumed |
| #7: A created; #9: B created | nothing | declined: both pairs are covered |
| #7: A created, B created | the pack changes B | a new pull request with A and the new B, saying A was declined in #7 |
| #7: A at v1 | A at v2 was merged, then the hub went back to v1 | a new pull request: v2 → v1 is another pair |
| #7: A created | the hub changed its id, the old branch is in branch_aliases |
declined: the fingerprint is the same |
| #7, closed by a stale bot | 30 days pass | a new pull request; a third bot close in a row counts as a decline |
A new pull request always carries everything the target is missing, declined pairs included: pack files belong together, and a partial delivery would leave the repository inconsistent. The overlap is named in its description.
A decline holds while nothing changed:
- the opt-in file is parsed the same — editing
packsorignoreis a new explicit choice and lifts every decline of that repository (comments and formatting don't); - no declined path became
localorignored— a team that made a file its own has answered for it.
An open sync pull request is stronger than the memory: touchmark updates it with the
current changes, or closes it as no-diff.
Bringing declined content back¶
When touchmark first sees a decline, it records it in the marker, adds a tick box to the description and leaves one comment saying what it remembered, when a new pull request would come, and how to undo it. Two writes, once. (Not on Bitbucket Cloud, where a declined pull request cannot be edited: see below.)
To undo a decline:
- reopen the pull request — an open pull request is stronger than the memory;
- tick Propose this content again in its description — touchmark marks it revoked and opens a new pull request with the current changes;
- from the hub, add a
forget_declinesentry to.touchmark/operations.ymland merge it through review (see One-off operations).
To refuse a file for good instead, add it to ignore, or set enabled: false in the opt-in
file (deleting it works too, unless the hub subscribed the repository) to stop
receiving anything.
On Bitbucket Cloud¶
A declined pull request on Bitbucket can never be edited or reopened, by anyone. touchmark writes nothing to it, and remembers the decline from what the marker held while the pull request was open:
- The opt-in state is recorded up front. Every pull request touchmark opens records
in its marker the state of the opt-in file it is proposed under, which the
acknowledgment records elsewhere. When the file changes while the pull request is
open, the next run records the new state, with one edit of the description even when
the proposed changes stay the same, and even when the target is blocked
(
branch-in-use,rules:*, …): when the run writes nothing else to the pull request, that edit changes only the marker. A push a branch restriction refuses at run time is followed by that edit too. - A decline holds while the opt-in file is parsed the same as that recorded state,
and lapses when the team edits
packsorignore, as an acknowledged decline does elsewhere. A declined path becominglocalorignoredlifts it too. - No comment, no tick box. touchmark leaves no comment on the declined pull request
(with nothing to record that it did, it would post one every run), and descriptions
carry no tick boxes there: Bitbucket shows the HTML comments they rest on as text. The
report says
declined, and the description's footnote names the way back. - Bringing declined content back is a
forget_declinesentry, or a change ofpacksorignore. touchmark cannot mark the pull request revoked, so the entry acts on every run while it is present: keep it until the pull request it brings is merged or closed. Removed earlier, the decline is in force again; an open pull request stays (an open pull request is stronger than memory), and its description then names the decline under Previously declined. - A marker without the opt-in state (one touchmark did not write in full) holds its
decline whatever the opt-in file says, since there is no state to compare with; the
report warns about it on every run and names the
forget_declinesentry that lifts it. - Who closed it counts as everywhere: Bitbucket names who declined a pull request. touchmark's own closes write the close into the description in the same edit that declines it; bots' closes wait for the cooldown, and the third in a row counts as a decline.
On Azure DevOps¶
touchmark never writes to an abandoned pull request on Azure DevOps either: whether its
properties, which hold the marker there, can still be changed is not known, and the
memory of Bitbucket Cloud needs no such write. Everything above
applies, with three differences: the marker lives in the property touchmark.marker
rather than the description, so the edit that records a new opt-in state changes only
that property; descriptions do carry the tick box Rebuild this branch while a branch is
paused; and touchmark never reactivates an abandoned pull request, though Azure DevOps
would let it.
On Bitbucket Data Center¶
Everything above applies, with three differences. A person may
reopen a declined pull request there: it is then touchmark's open pull request again,
and no longer a decline; touchmark itself never reopens one. Bitbucket declines a pull
request without activity for four weeks by default, as its system user, which touchmark
counts as a bot: such a close waits for the cooldown, as a stale bot's does. And a user
who may only read a repository may decline its pull requests, the reader included: list
the reader in automation_accounts, so that a decline made with its token counts as a
bot's, not as the team's (plan warns until it is there).
Limits¶
- Only the last 50 closed pull requests on the sync branches count.
- The marker holds the full list of pairs as long as it fits 48 KiB; beyond that it keeps only the content key, and a decline then covers exactly the same set of changes.
- GitLab names who closed a merge request with a delay after a branch is deleted. When a person deletes the sync branch while GitLab is still processing touchmark's push, GitLab can record the writer as the closer, and the close then counts as touchmark's own: that decline is lost and the content is proposed again.
- Closed pull requests of the multi-gitter era, without a marker, are never declines: their content is unknown.
- On Bitbucket Cloud the opt-in state of a decline is the one recorded by the last run
before the decline, whatever that run decided for the target. When the team changes
packsorignoreand declines the pull request before touchmark runs again, the decline counts from the earlier state and has lapsed already: the content is proposed once more, under the new choice. A blocked target does not widen that window: its run records the state as well. Only a run that writes nothing to the target at all (a failed or deferred target,blocked:mass-close) leaves it open until the next run.