Add agent workflows & stuff
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
import { ConvexError, v } from 'convex/values';
|
||||
|
||||
import type { Id } from './_generated/dataModel';
|
||||
import {
|
||||
internalMutation,
|
||||
internalQuery,
|
||||
mutation,
|
||||
query,
|
||||
} from './_generated/server';
|
||||
import { getRequiredUserId } from './model';
|
||||
|
||||
export const getInstallUrl = query({
|
||||
args: {},
|
||||
handler: () => {
|
||||
const slug = process.env.GITHUB_APP_SLUG;
|
||||
if (!slug) return null;
|
||||
return `https://github.com/apps/${slug}/installations/new`;
|
||||
},
|
||||
});
|
||||
|
||||
export const getConnection = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const userId = await getRequiredUserId(ctx);
|
||||
return await ctx.db
|
||||
.query('gitConnections')
|
||||
.withIndex('by_user_provider', (q) =>
|
||||
q.eq('userId', userId).eq('provider', 'github'),
|
||||
)
|
||||
.first();
|
||||
},
|
||||
});
|
||||
|
||||
export const connectInstallation = mutation({
|
||||
args: { installationId: v.string() },
|
||||
handler: async (ctx, { installationId }) => {
|
||||
const userId = await getRequiredUserId(ctx);
|
||||
const trimmedInstallationId = installationId.trim();
|
||||
if (!trimmedInstallationId) {
|
||||
throw new ConvexError('GitHub installation ID is required.');
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const existing = await ctx.db
|
||||
.query('gitConnections')
|
||||
.withIndex('by_user_provider', (q) =>
|
||||
q.eq('userId', userId).eq('provider', 'github'),
|
||||
)
|
||||
.first();
|
||||
|
||||
const patch = {
|
||||
provider: 'github' as const,
|
||||
displayName: `GitHub installation ${trimmedInstallationId}`,
|
||||
installationId: trimmedInstallationId,
|
||||
scopes: [
|
||||
'metadata:read',
|
||||
'administration:write',
|
||||
'contents:write',
|
||||
'pull_requests:write',
|
||||
],
|
||||
status: 'active' as const,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
if (existing) {
|
||||
await ctx.db.patch(existing._id, patch);
|
||||
return existing._id;
|
||||
}
|
||||
|
||||
return await ctx.db.insert('gitConnections', {
|
||||
userId,
|
||||
...patch,
|
||||
connectedAt: now,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const getConnectionForUser = internalQuery({
|
||||
args: { userId: v.id('users') },
|
||||
handler: async (ctx, { userId }) => {
|
||||
return await ctx.db
|
||||
.query('gitConnections')
|
||||
.withIndex('by_user_provider', (q) =>
|
||||
q.eq('userId', userId).eq('provider', 'github'),
|
||||
)
|
||||
.first();
|
||||
},
|
||||
});
|
||||
|
||||
export const upsertConnectionForUser = internalMutation({
|
||||
args: {
|
||||
userId: v.id('users'),
|
||||
providerAccountId: v.optional(v.string()),
|
||||
displayName: v.string(),
|
||||
username: v.optional(v.string()),
|
||||
avatarUrl: v.optional(v.string()),
|
||||
installationId: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const now = Date.now();
|
||||
const existing = await ctx.db
|
||||
.query('gitConnections')
|
||||
.withIndex('by_user_provider', (q) =>
|
||||
q.eq('userId', args.userId).eq('provider', 'github'),
|
||||
)
|
||||
.first();
|
||||
|
||||
const patch = {
|
||||
providerAccountId: args.providerAccountId,
|
||||
displayName: args.displayName,
|
||||
username: args.username,
|
||||
avatarUrl: args.avatarUrl,
|
||||
installationId: args.installationId,
|
||||
scopes: [
|
||||
'metadata:read',
|
||||
'administration:write',
|
||||
'contents:write',
|
||||
'pull_requests:write',
|
||||
'checks:write',
|
||||
'statuses:write',
|
||||
'issues:write',
|
||||
],
|
||||
status: 'active' as const,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
if (existing) {
|
||||
await ctx.db.patch(existing._id, patch);
|
||||
return existing._id;
|
||||
}
|
||||
|
||||
return await ctx.db.insert('gitConnections', {
|
||||
userId: args.userId,
|
||||
provider: 'github',
|
||||
...patch,
|
||||
connectedAt: now,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const createForkSpoonRecord = internalMutation({
|
||||
args: {
|
||||
ownerId: v.id('users'),
|
||||
name: v.string(),
|
||||
description: v.optional(v.string()),
|
||||
upstreamOwner: v.string(),
|
||||
upstreamRepo: v.string(),
|
||||
upstreamDefaultBranch: v.string(),
|
||||
upstreamUrl: v.string(),
|
||||
forkOwner: v.string(),
|
||||
forkRepo: v.string(),
|
||||
forkDefaultBranch: v.string(),
|
||||
forkUrl: v.string(),
|
||||
visibility: v.union(
|
||||
v.literal('public'),
|
||||
v.literal('private'),
|
||||
v.literal('internal'),
|
||||
v.literal('unknown'),
|
||||
),
|
||||
connectionId: v.optional(v.id('gitConnections')),
|
||||
},
|
||||
handler: async (ctx, args): Promise<Id<'spoons'>> => {
|
||||
const now = Date.now();
|
||||
const spoonId = await ctx.db.insert('spoons', {
|
||||
ownerId: args.ownerId,
|
||||
name: args.name,
|
||||
description: args.description,
|
||||
provider: 'github',
|
||||
upstreamOwner: args.upstreamOwner,
|
||||
upstreamRepo: args.upstreamRepo,
|
||||
upstreamDefaultBranch: args.upstreamDefaultBranch,
|
||||
upstreamUrl: args.upstreamUrl,
|
||||
forkOwner: args.forkOwner,
|
||||
forkRepo: args.forkRepo,
|
||||
forkDefaultBranch: args.forkDefaultBranch,
|
||||
forkUrl: args.forkUrl,
|
||||
visibility: args.visibility,
|
||||
maintenanceMode: 'watch',
|
||||
syncCadence: 'daily',
|
||||
productionRefStrategy: 'default_branch',
|
||||
status: 'active',
|
||||
syncStatus: 'unknown',
|
||||
connectionId: args.connectionId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
await ctx.db.insert('spoonSettings', {
|
||||
spoonId,
|
||||
ownerId: args.ownerId,
|
||||
autoRefreshEnabled: true,
|
||||
autoReviewEnabled: true,
|
||||
autoSyncEnabled: false,
|
||||
requireAiLowRiskForSync: true,
|
||||
requireCleanCompareForSync: true,
|
||||
ignoredFilePatterns: [],
|
||||
importantFilePatterns: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
await ctx.db.insert('syncRuns', {
|
||||
spoonId,
|
||||
ownerId: args.ownerId,
|
||||
kind: 'manual_check',
|
||||
status: 'clean',
|
||||
summary: `Created GitHub fork ${args.forkOwner}/${args.forkRepo} from ${args.upstreamOwner}/${args.upstreamRepo}.`,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
return spoonId;
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user