feat(tasks): Aufgabe als Git-Issue anlegen, Zustand wandert mit
Die Zuordnung stand im Schema laengst – sourceIssue, sourceUrl und sourceRepositoryId samt Eindeutigkeit je Repository, gefuellt von der Uebernahme aus Issues seit v0.9.0. Es fehlte die Gegenrichtung. Ein Knopf im Aufgabendialog legt das Issue an; Nummer und Adresse landen in denselben Feldern, der Dublettenschutz gilt also fuer beide Wege. In den Rumpf kommt ein Rueckverweis auf das Projekt. Ausdruecklich per Knopf und nie nebenbei: was in ein fremdes System geschrieben wird, soll jemand gewollt haben. Ist die Aufgabe erst verknuepft, wandert der Zustand allerdings mit – erledigt schliesst das Issue, ein Zurueckziehen oeffnet es wieder. Fehlertolerant: ein nicht erreichbares Git-System darf das Abhaken nicht verhindern. Die Zustaende passen nicht aufeinander, und das bleibt so. Nebula kennt vier, ein Issue zwei; nach aussen geht nur die Grenze um ERLEDIGT. Ein Rundlauf verliert damit IN ARBEIT und BLOCKIERT. Labels waeren die Alternative, wuerden aber den Issue-Tracker mit Zustaenden fuellen, die dort niemand pflegt. Kein Widerspruch zu "keine eigenen Git-Operationen": Issues laufen ueber die HTTP-API der Provider. Dafuer gibt es jetzt sendJson neben getJson – durch dieselbe SSRF-Schleuse, aber ohne Umleitungen zu folgen. Ein 307 auf eine interne Adresse naehme den Rumpf und den Token im Header mit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { issueShouldBeOpen, statusForIssueState } from "./issues";
|
||||
|
||||
describe("issueShouldBeOpen", () => {
|
||||
it("haelt das Issue offen, solange die Aufgabe nicht erledigt ist", () => {
|
||||
expect(issueShouldBeOpen("TODO")).toBe(true);
|
||||
expect(issueShouldBeOpen("DOING")).toBe(true);
|
||||
expect(issueShouldBeOpen("BLOCKED")).toBe(true);
|
||||
});
|
||||
|
||||
it("schliesst es erst bei ERLEDIGT", () => {
|
||||
expect(issueShouldBeOpen("DONE")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("statusForIssueState", () => {
|
||||
it("macht aus einem geschlossenen Issue eine erledigte Aufgabe", () => {
|
||||
expect(statusForIssueState(false, "TODO")).toBe("DONE");
|
||||
expect(statusForIssueState(false, "DOING")).toBe("DONE");
|
||||
});
|
||||
|
||||
it("holt eine erledigte Aufgabe zurueck nach OFFEN", () => {
|
||||
expect(statusForIssueState(true, "DONE")).toBe("TODO");
|
||||
});
|
||||
|
||||
it("laesst den feineren Zustand stehen, wenn das Issue ohnehin offen ist", () => {
|
||||
// Ein "opened"-Ereignis zu einer Aufgabe, die schon in Arbeit ist, darf
|
||||
// sie nicht auf OFFEN zuruecksetzen – IN ARBEIT ist mehr Information.
|
||||
expect(statusForIssueState(true, "DOING")).toBe("DOING");
|
||||
expect(statusForIssueState(true, "BLOCKED")).toBe("BLOCKED");
|
||||
expect(statusForIssueState(true, "TODO")).toBe("TODO");
|
||||
});
|
||||
|
||||
it("bildet den Rundlauf ab, so verlustbehaftet wie er ist", () => {
|
||||
// IN ARBEIT geht nach draussen als "offen". Kommt es zurueck, bleibt es
|
||||
// IN ARBEIT – der Zustand ueberlebt also, solange niemand das Issue
|
||||
// schliesst. Nach dem Schliessen und Wiederoeffnen ist er weg, und das
|
||||
// ist die bewusst hingenommene Grenze.
|
||||
const hin = issueShouldBeOpen("DOING");
|
||||
expect(statusForIssueState(hin, "DOING")).toBe("DOING");
|
||||
expect(statusForIssueState(true, statusForIssueState(false, "DOING"))).toBe("TODO");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user