Browse Source
Nostr-Signature: e036526abc826e4435a562f1f334e594577d78a7a50a02cb78f8e5565ea68872 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 12642202ef028dfbac68ce53e9cf9f7a64ce3242d2dd995fd0b4c4014c9aa2b18891b72dc281fa5aadacd636646ebd8d2b69fd29bf36407658dff9725b779be5main
11 changed files with 1017 additions and 30 deletions
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/** |
||||
* API endpoint for merging Pull Requests |
||||
*/ |
||||
|
||||
import { json } from '@sveltejs/kit'; |
||||
import type { RequestHandler } from './$types'; |
||||
import { withRepoValidation } from '$lib/utils/api-handlers.js'; |
||||
import type { RepoRequestContext } from '$lib/utils/api-context.js'; |
||||
import { handleValidationError, handleApiError } from '$lib/utils/error-handler.js'; |
||||
import { DEFAULT_NOSTR_RELAYS } from '$lib/config.js'; |
||||
import { RepoManager } from '$lib/services/git/repo-manager.js'; |
||||
import { FileManager } from '$lib/services/git/file-manager.js'; |
||||
import { MaintainerService } from '$lib/services/nostr/maintainer-service.js'; |
||||
import { prsService } from '$lib/services/service-registry.js'; |
||||
import { simpleGit } from 'simple-git'; |
||||
import { join, resolve } from 'path'; |
||||
import { existsSync } from 'fs'; |
||||
import logger from '$lib/services/logger.js'; |
||||
|
||||
const repoRoot = process.env.GIT_REPO_ROOT || '/repos'; |
||||
const repoManager = new RepoManager(repoRoot); |
||||
const fileManager = new FileManager(repoRoot); |
||||
const maintainerService = new MaintainerService(DEFAULT_NOSTR_RELAYS); |
||||
|
||||
export const POST: RequestHandler = withRepoValidation( |
||||
async ({ repoContext, requestContext, event }) => { |
||||
const body = await event.request.json(); |
||||
const { prId, prAuthor, prCommitId, targetBranch = 'main', mergeMessage } = body; |
||||
|
||||
if (!prId || !prAuthor || !prCommitId) { |
||||
throw handleValidationError('Missing required fields: prId, prAuthor, prCommitId', { operation: 'mergePR', npub: repoContext.npub, repo: repoContext.repo }); |
||||
} |
||||
|
||||
// Check if user is maintainer
|
||||
const isMaintainer = await maintainerService.isMaintainer(requestContext.userPubkeyHex || '', repoContext.repoOwnerPubkey, repoContext.repo); |
||||
|
||||
if (!isMaintainer && requestContext.userPubkeyHex !== repoContext.repoOwnerPubkey) { |
||||
throw handleApiError(new Error('Only repository owners and maintainers can merge PRs'), { operation: 'mergePR', npub: repoContext.npub, repo: repoContext.repo }, 'Unauthorized'); |
||||
} |
||||
|
||||
// Check if repo exists locally
|
||||
const repoPath = join(repoRoot, repoContext.npub, `${repoContext.repo}.git`); |
||||
if (!existsSync(repoPath)) { |
||||
throw handleApiError(new Error('Repository not cloned locally. Please clone the repository first.'), { operation: 'mergePR', npub: repoContext.npub, repo: repoContext.repo }, 'Repository not found'); |
||||
} |
||||
|
||||
// Get user info for commit
|
||||
const authorName = requestContext.userName || 'GitRepublic User'; |
||||
const authorEmail = requestContext.userEmail || `${requestContext.userPubkeyHex?.slice(0, 20)}@gitrepublic.web`; |
||||
|
||||
try { |
||||
const git = simpleGit(repoPath); |
||||
|
||||
// Fetch latest changes
|
||||
await git.fetch(['origin']).catch(() => {}); // Ignore errors if no remote
|
||||
|
||||
// Checkout target branch
|
||||
await git.checkout(targetBranch); |
||||
|
||||
// Merge the PR commit
|
||||
const mergeMessageText = mergeMessage || `Merge pull request ${prId.slice(0, 7)}`; |
||||
await git.merge([prCommitId, '--no-ff', '-m', mergeMessageText]); |
||||
|
||||
// Get the merge commit ID
|
||||
const mergeCommitId = (await git.revparse(['HEAD'])).trim(); |
||||
|
||||
// Update PR status to merged
|
||||
const statusEvent = await prsService.updatePRStatus( |
||||
prId, |
||||
prAuthor, |
||||
repoContext.repoOwnerPubkey, |
||||
repoContext.repo, |
||||
'merged', |
||||
mergeCommitId |
||||
); |
||||
|
||||
return json({
|
||||
success: true,
|
||||
mergeCommitId, |
||||
statusEvent
|
||||
}); |
||||
} catch (err) { |
||||
logger.error({ error: err, npub: repoContext.npub, repo: repoContext.repo, prId, prCommitId }, 'Error merging PR'); |
||||
throw handleApiError(err instanceof Error ? err : new Error('Failed to merge PR'), { operation: 'mergePR', npub: repoContext.npub, repo: repoContext.repo }, 'Failed to merge pull request'); |
||||
} |
||||
}, |
||||
{ operation: 'mergePR', requireRepoAccess: true } |
||||
); |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/** |
||||
* API endpoint for updating Pull Requests (kind 1619) |
||||
*/ |
||||
|
||||
import { json } from '@sveltejs/kit'; |
||||
// @ts-ignore - SvelteKit generates this type
|
||||
import type { RequestHandler } from './$types'; |
||||
import { withRepoValidation } from '$lib/utils/api-handlers.js'; |
||||
import type { RepoRequestContext } from '$lib/utils/api-context.js'; |
||||
import { handleValidationError, handleApiError } from '$lib/utils/error-handler.js'; |
||||
import { DEFAULT_NOSTR_RELAYS } from '$lib/config.js'; |
||||
import { prsService } from '$lib/services/service-registry.js'; |
||||
import { getGitUrl } from '$lib/config.js'; |
||||
|
||||
export const POST: RequestHandler = withRepoValidation( |
||||
async ({ repoContext, requestContext, event }) => { |
||||
const body = await event.request.json(); |
||||
const { prId, prAuthor, newCommitId, mergeBase } = body; |
||||
|
||||
if (!prId || !prAuthor || !newCommitId) { |
||||
throw handleValidationError('Missing required fields: prId, prAuthor, newCommitId', { operation: 'updatePR', npub: repoContext.npub, repo: repoContext.repo }); |
||||
} |
||||
|
||||
// Only PR author can update their PR
|
||||
if (requestContext.userPubkeyHex !== prAuthor) { |
||||
throw handleApiError(new Error('Only the PR author can update the PR'), { operation: 'updatePR', npub: repoContext.npub, repo: repoContext.repo }, 'Unauthorized'); |
||||
} |
||||
|
||||
const cloneUrl = getGitUrl(repoContext.npub, repoContext.repo); |
||||
const updateEvent = await prsService.updatePullRequest( |
||||
prId, |
||||
prAuthor, |
||||
repoContext.repoOwnerPubkey, |
||||
repoContext.repo, |
||||
newCommitId, |
||||
cloneUrl, |
||||
mergeBase |
||||
); |
||||
|
||||
return json({ success: true, event: updateEvent }); |
||||
}, |
||||
{ operation: 'updatePR', requireRepoAccess: false } |
||||
); |
||||
Loading…
Reference in new issue