kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
at main 148 lines 3.8 kB view raw
1import type { GitHubConfig } from "../config"; 2import { createOrUpdateExternalLink } from "../services/link-manager"; 3import { 4 findAllIntegrationsByRepo, 5 findTaskByNumber, 6 isTaskInFinalState, 7 updateTaskStatus, 8} from "../services/task-service"; 9import { extractTaskNumberFromBranch } from "../utils/branch-matcher"; 10import { resolveTargetStatus } from "../utils/resolve-column"; 11 12type PushPayload = { 13 ref: string; 14 head_commit?: { 15 id: string; 16 message: string; 17 author?: { name: string }; 18 timestamp: string; 19 }; 20 repository: { 21 owner: { login: string }; 22 name: string; 23 html_url: string; 24 }; 25}; 26 27const PROTECTED_BRANCHES = [ 28 "main", 29 "master", 30 "develop", 31 "staging", 32 "production", 33]; 34 35export async function handlePush(payload: PushPayload) { 36 const { ref, repository, head_commit } = payload; 37 38 const branchName = ref.replace("refs/heads/", ""); 39 console.log(`[Push] Processing branch: ${branchName}`); 40 41 if (PROTECTED_BRANCHES.includes(branchName)) { 42 console.log(`[Push] Skipping protected branch: ${branchName}`); 43 return; 44 } 45 46 const integrations = await findAllIntegrationsByRepo( 47 repository.owner.login, 48 repository.name, 49 ); 50 51 if (integrations.length === 0) { 52 console.log( 53 `[Push] No integrations found for ${repository.owner.login}/${repository.name}`, 54 ); 55 return; 56 } 57 58 console.log( 59 `[Push] Found ${integrations.length} integration(s) for this repo`, 60 ); 61 62 for (const integration of integrations) { 63 if (!integration.project) { 64 continue; 65 } 66 67 const config = JSON.parse(integration.config) as GitHubConfig; 68 const projectSlug = integration.project.slug; 69 console.log( 70 `[Push] Trying project: ${projectSlug}, pattern: ${config.branchPattern}`, 71 ); 72 73 const taskNumber = extractTaskNumberFromBranch( 74 branchName, 75 config, 76 projectSlug, 77 ); 78 79 if (!taskNumber) { 80 console.log( 81 `[Push] Could not extract task number from branch: ${branchName} (pattern: ${config.branchPattern}, slug: ${projectSlug})`, 82 ); 83 continue; 84 } 85 86 console.log( 87 `[Push] Extracted task number: ${taskNumber} for project ${projectSlug}`, 88 ); 89 90 const task = await findTaskByNumber(integration.projectId, taskNumber); 91 92 if (!task) { 93 console.log( 94 `[Push] Task #${taskNumber} not found in project ${integration.projectId}`, 95 ); 96 continue; 97 } 98 99 console.log( 100 `[Push] Found task: ${task.id}, current status: ${task.status}`, 101 ); 102 103 await createOrUpdateExternalLink({ 104 taskId: task.id, 105 integrationId: integration.id, 106 resourceType: "branch", 107 externalId: branchName, 108 url: `${repository.html_url}/tree/${branchName}`, 109 title: branchName, 110 metadata: { 111 lastCommit: head_commit 112 ? { 113 sha: head_commit.id, 114 message: head_commit.message, 115 author: head_commit.author?.name, 116 timestamp: head_commit.timestamp, 117 } 118 : null, 119 }, 120 }); 121 122 const targetStatus = await resolveTargetStatus( 123 integration.projectId, 124 "branch_push", 125 config.statusTransitions?.onBranchPush || "in-progress", 126 ); 127 console.log( 128 `[Push] Target status: ${targetStatus}, current: ${task.status}`, 129 ); 130 131 const isTaskFinal = await isTaskInFinalState(task); 132 133 if (task.status !== targetStatus && !isTaskFinal) { 134 console.log( 135 `[Push] Updating task ${task.id} status from ${task.status} to ${targetStatus}`, 136 ); 137 await updateTaskStatus(task.id, targetStatus); 138 } else { 139 console.log(`[Push] Skipping status update - already ${task.status}`); 140 } 141 142 return; 143 } 144 145 console.log( 146 `[Push] No matching task found in any integrated project for branch: ${branchName}`, 147 ); 148}