1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
import { Hono } from "hono";
import { eq, and } from "drizzle-orm";
import { db } from "../db";
import { repositories, users, activityFeed } from "../db/schema";
import { softAuth, requireAuth } from "../middleware/auth";
import type { AuthEnv } from "../middleware/auth";
import { getRepoPath, repoExists, initBareRepo } from "../git/repository";
import { config } from "../lib/config";
import { join } from "path";
const fork = new Hono<AuthEnv>();
fork.use("*", softAuth);
fork.post("/:owner/:repo/fork", requireAuth, async (c) => {
const { owner: ownerName, repo: repoName } = c.req.param();
const user = c.get("user")!;
if (ownerName === user.username) {
return c.redirect(`/${ownerName}/${repoName}`);
}
if (!(await repoExists(ownerName, repoName))) {
return c.redirect(`/${ownerName}/${repoName}`);
}
if (await repoExists(user.username, repoName)) {
return c.redirect(`/${user.username}/${repoName}`);
}
const [sourceOwner] = await db
.select()
.from(users)
.where(eq(users.username, ownerName))
.limit(1);
if (!sourceOwner) return c.redirect(`/${ownerName}/${repoName}`);
const [sourceRepo] = await db
.select()
.from(repositories)
.where(
and(
eq(repositories.ownerId, sourceOwner.id),
eq(repositories.name, repoName)
)
)
.limit(1);
if (!sourceRepo) return c.redirect(`/${ownerName}/${repoName}`);
const sourcePath = getRepoPath(ownerName, repoName);
const destPath = join(config.gitReposPath, user.username, `${repoName}.git`);
const proc = Bun.spawn(["git", "clone", "--bare", sourcePath, destPath], {
stdout: "pipe",
stderr: "pipe",
});
await proc.exited;
await db.insert(repositories).values({
name: repoName,
ownerId: user.id,
description: sourceRepo.description
? `Fork of ${ownerName}/${repoName} — ${sourceRepo.description}`
: `Fork of ${ownerName}/${repoName}`,
isPrivate: false,
defaultBranch: sourceRepo.defaultBranch,
diskPath: destPath,
forkedFromId: sourceRepo.id,
});
await db
.update(repositories)
.set({ forkCount: sourceRepo.forkCount + 1 })
.where(eq(repositories.id, sourceRepo.id));
try {
await db.insert(activityFeed).values({
repositoryId: sourceRepo.id,
userId: user.id,
action: "fork",
metadata: JSON.stringify({ forkOwner: user.username }),
});
} catch {
}
return c.redirect(`/${user.username}/${repoName}`);
});
export default fork;
|