kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import type { GiteaConfig } from "../config";
2import { createGiteaClient, type GiteaLabel } from "./gitea-api";
3
4const labelColors: Record<string, string> = {
5 "priority:low": "0EA5E9",
6 "priority:medium": "EAB308",
7 "priority:high": "F97316",
8 "priority:urgent": "EF4444",
9 "status:to-do": "6B7280",
10 "status:in-progress": "3B82F6",
11 "status:in-review": "8B5CF6",
12 "status:done": "10B981",
13 "status:planned": "8B5CF6",
14 "status:archived": "6B7280",
15};
16
17function getLabelColor(labelName: string): string {
18 return labelColors[labelName] || "6B7280";
19}
20
21export async function ensureLabelsExistGitea(
22 config: GiteaConfig,
23 labels: string[],
24): Promise<Map<string, number>> {
25 const client = createGiteaClient(config);
26 const map = new Map<string, number>();
27 const { repositoryOwner, repositoryName } = config;
28
29 let existingLabels: GiteaLabel[];
30 try {
31 existingLabels = await client.listLabels(repositoryOwner, repositoryName);
32 } catch (error) {
33 console.error("Failed to list Gitea labels for ensureLabelsExistGitea", {
34 repositoryOwner,
35 repositoryName,
36 error,
37 });
38 return map;
39 }
40
41 const nameToId = new Map(existingLabels.map((l) => [l.name, l.id]));
42
43 for (const name of labels) {
44 try {
45 const existingId = nameToId.get(name);
46 if (existingId !== undefined) {
47 map.set(name, existingId);
48 continue;
49 }
50
51 const color = getLabelColor(name);
52 const created = await client.createLabel(
53 repositoryOwner,
54 repositoryName,
55 name,
56 color,
57 );
58 nameToId.set(name, created.id);
59 map.set(name, created.id);
60 } catch (error) {
61 console.error(`Failed to ensure Gitea label "${name}":`, error);
62 }
63 }
64 return map;
65}
66
67export async function addLabelsToIssueGitea(
68 config: GiteaConfig,
69 issueIndex: number,
70 labelNames: string[],
71) {
72 if (labelNames.length === 0) return;
73
74 const nameToId = await ensureLabelsExistGitea(config, labelNames);
75 const ids: number[] = [];
76 for (const name of labelNames) {
77 const id = nameToId.get(name);
78 if (id !== undefined) {
79 ids.push(id);
80 }
81 }
82
83 if (ids.length === 0) return;
84
85 const client = createGiteaClient(config);
86
87 try {
88 await client.addLabelsToIssue(
89 config.repositoryOwner,
90 config.repositoryName,
91 issueIndex,
92 ids,
93 );
94 } catch (error) {
95 console.error("Failed to add labels to Gitea issue:", error);
96 }
97}
98
99export async function removeLabelGitea(
100 config: GiteaConfig,
101 issueIndex: number,
102 labelName: string,
103) {
104 const client = createGiteaClient(config);
105 let labels: GiteaLabel[];
106 try {
107 labels = await client.listLabels(
108 config.repositoryOwner,
109 config.repositoryName,
110 );
111 } catch (error) {
112 console.error("Failed to list Gitea labels for removal:", {
113 repositoryOwner: config.repositoryOwner,
114 repositoryName: config.repositoryName,
115 issueIndex,
116 labelName,
117 error,
118 });
119 return;
120 }
121
122 const label = labels.find((l) => l.name === labelName);
123 if (!label) return;
124
125 try {
126 await client.removeLabelFromIssue(
127 config.repositoryOwner,
128 config.repositoryName,
129 issueIndex,
130 label.id,
131 );
132 } catch (error) {
133 console.error("Failed to remove label from Gitea issue:", {
134 repositoryOwner: config.repositoryOwner,
135 repositoryName: config.repositoryName,
136 issueIndex,
137 labelName,
138 labelId: label.id,
139 error,
140 });
141 }
142}