#2698. A list synced from GitLab gets a Sync option of its own, off by
default: Write changes back to GitLab. With it, every Sync run first
sends what members did on the list's cards, then reads GitLab, so the
read finds both sides agreeing:
- a title or description edited in WeKan, when the issue still has the
text both sides last agreed on - the local-only edit the reconcile
already keeps. The Source footer Sync adds is not sent; when both sides
changed, nothing is written and it stays a conflict to resolve;
- a card archived in WeKan closes its open issue, and restoring a card
WeKan closed reopens it (syncClosedByWeKan); an issue GitLab closed is
never reopened by WeKan;
- a comment written in WeKan becomes a note, and keeps the note's id
(syncCommentId) so the comments sync does not bring it back twice.
Only what happens after it was switched on is sent (writeBackSince), at
most 100 writes a run. Every write is fenced by the list's Sync
reservation, goes through the same address checks as the reads (no
redirects, PUT or POST to an issue or its notes only), and records on
the WeKan side only while the card or comment is still as planned. A
refused write is shown in the Sync popup (syncWriteBackError, beside
syncSource because the run's list writes match syncSource whole) and the
read sync still runs. Not in Sandstorm, whose bridge only reads.
Tests: tests/listSyncWriteBack.test.cjs (the plan with GitLab's shapes,
the parser's footer, every negative - conflict, legacy card, old
archive or comment, foreign card, issue GitLab closed - and the wiring),
server/lib/tests/listSyncWriteBack.tests.js (end to end through
syncOneList against a fake GitLab). The live test,
releases/live-tests/gitlab-write-back.mjs, runs from build.sh / build.bat
-> Tests -> Live tests with the glab login releases/mirror.sh uses, on one
scratch issue in a private project of that account; it is human-run and
was not run here. releases/live-tests/run.mjs runs every live test and
skips a service with no login.
Also: the English variants get the SQRL and Windows sign-in strings
(their key order follows en.i18n.json); buildScriptParity accounts for
the scripts CI runs inside their own environments; new strings
translated in all locales.
Thanks to xet7 !
Since #1759 a card copied or moved to another board brings its labels: a
label that board lacks is created there when the actor is its admin. The
stored (durable) rule copyCard, move to another board and move-all onto
another board still matched by name only and dropped the rest, so the
durable copy or move was no longer the ordinary one - the parity three
server tests check - and the card lost a label a direct copy would keep.
The durable plans now use the same planCrossBoardLabels with the rule's
actor. The labels to create are saved in the command (copy) or move
(single move, and each move-all unit), so a replay creates nothing twice:
each is pushed only when no label with its id is on that board yet, before
the card that names it is written. In a move-all, a label created for one
card is that board's label for the next, as when Card.move moves them one
by one. Commands saved before this, without the labels, still validate.
The server tests now expect the created label, once across a replay, and
the ordinary copy or move finding it; the card-move test gains the negative
of a mover who is not the new board's admin, where the label is dropped and
its activity removed. The command tests cover the new field, its validation
and an older command without it.
Thanks to xet7 !
A copyCard rule that copies onto another board now uses the same saved
command, with that board as its target: the copy takes that board's
labels of the same name, its custom fields as Card.copy maps them, its
card number and the dependencies that stay on it. Its checklists, items,
subtasks, comments and attachments are all placed on that board. As
with links, eligibility requires the destination to have opted in and
to have only durable rules of its own, and the runner checks it again.
The server test compares the result with the ordinary Card.copy to the
same board.
Thanks to xet7 !
A copyCard rule that copies onto the card's own board now has a saved
command. What the copy contains is decided once, with the ordinary
copy's own helpers: the card as Card.copy builds it (the custom fields
the actor may read, its dependencies on the board, its Scrum metadata,
a new card number, the bottom of the list), its live attachments, its
checklists and items, its subtasks with their checklists, and its
comments. Every document gets an id derived from the rule invocation,
so a replay inserts each once. The copy's and its subtasks' creation
activities are saved and delivered durably; each attachment file is
copied once (copyFile can now be given the id) and its History row is
written from the stored attachment; checklists, items and comments are
direct inserts, as Card.copy makes them. The cover is remapped to the
copied attachment by its derived id. Like the ordinary copy chain
guard, a copy whose own creation triggers the same action is not copied
again. A copy to another board keeps the board on direct Sync.
The server test copies a card with all of those, replays it, checks the
chain guard, and compares the result with the ordinary Card.copy.
Thanks to xet7 !