(projectId: string)
| 218 | } |
| 219 | |
| 220 | export async function pushProjectToGitHub(projectId: string) { |
| 221 | try { |
| 222 | const project = await getProjectById(projectId); |
| 223 | if (!project) { |
| 224 | throw new Error('Project not found'); |
| 225 | } |
| 226 | |
| 227 | const token = await getPlainServiceToken('github'); |
| 228 | if (!token) { |
| 229 | throw new GitHubError('GitHub token not configured', 401); |
| 230 | } |
| 231 | |
| 232 | const service = await getProjectService(projectId, 'github'); |
| 233 | const data = service?.serviceData as Record<string, any> | undefined; |
| 234 | if (!data?.clone_url || !data?.owner) { |
| 235 | throw new GitHubError('GitHub repository not connected', 404); |
| 236 | } |
| 237 | |
| 238 | const repoPath = await ensureProjectRepository(projectId, project.repoPath); |
| 239 | ensureGitRepository(repoPath); |
| 240 | const authenticatedUrl = String(data.clone_url).replace('https://', `https://${data.owner}:${token}@`); |
| 241 | const user = await getGithubUser(); |
| 242 | const userName = user.name || user.login; |
| 243 | const userEmail = user.email || `${user.login}@users.noreply.github.com`; |
| 244 | ensureGitConfig(repoPath, userName, userEmail); |
| 245 | addOrUpdateRemote(repoPath, 'origin', authenticatedUrl); |
| 246 | const committed = commitAll(repoPath, 'Update from Claudable'); |
| 247 | if (!committed) { |
| 248 | console.log('[GitHubService] No changes to commit before push'); |
| 249 | } |
| 250 | |
| 251 | pushToRemote(repoPath, 'origin', data.default_branch || 'main'); |
| 252 | |
| 253 | await updateProjectServiceData(projectId, 'github', { |
| 254 | last_pushed_at: new Date().toISOString(), |
| 255 | }); |
| 256 | } catch (error) { |
| 257 | if (error instanceof GitHubError) { |
| 258 | throw error; |
| 259 | } |
| 260 | const message = error instanceof Error ? error.message : 'Unknown error'; |
| 261 | throw new GitHubError(`Failed to push project to GitHub: ${message}`); |
| 262 | } |
| 263 | } |
no test coverage detected