pierre-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/api/plugins/error-handler.js +40 -0
- package/dist/api/routes/health.js +7 -0
- package/dist/api/routes/me.js +34 -0
- package/dist/api/routes/mergers.js +7 -0
- package/dist/api/routes/open-prs.js +21 -0
- package/dist/api/routes/prs.js +50 -0
- package/dist/api/routes/repos.js +188 -0
- package/dist/api/routes/threads.js +20 -0
- package/dist/api/routes/timeline.js +73 -0
- package/dist/api/routes/users.js +28 -0
- package/dist/app.js +48 -0
- package/dist/ascii.js +12 -0
- package/dist/cli.js +138 -0
- package/dist/config.js +41 -0
- package/dist/db/cleanup.js +22 -0
- package/dist/db/client.js +13 -0
- package/dist/db/migrate.js +15 -0
- package/dist/db/migrations/0000_purple_ben_grimm.sql +155 -0
- package/dist/db/migrations/0001_colorful_ozymandias.sql +31 -0
- package/dist/db/migrations/0002_famous_sersi.sql +9 -0
- package/dist/db/migrations/0003_clever_shinobi_shaw.sql +3 -0
- package/dist/db/migrations/0004_pale_scalphunter.sql +1 -0
- package/dist/db/migrations/0005_daffy_guardian.sql +2 -0
- package/dist/db/migrations/meta/0000_snapshot.json +1116 -0
- package/dist/db/migrations/meta/0001_snapshot.json +1321 -0
- package/dist/db/migrations/meta/0002_snapshot.json +1375 -0
- package/dist/db/migrations/meta/0003_snapshot.json +1396 -0
- package/dist/db/migrations/meta/0004_snapshot.json +1416 -0
- package/dist/db/migrations/meta/0005_snapshot.json +1430 -0
- package/dist/db/migrations/meta/_journal.json +48 -0
- package/dist/db/queries.js +837 -0
- package/dist/db/run-migrations.js +10 -0
- package/dist/db/schema.js +248 -0
- package/dist/db/triage.js +168 -0
- package/dist/github/auth.js +19 -0
- package/dist/github/client.js +30 -0
- package/dist/github/local-user.js +92 -0
- package/dist/github/queries.js +249 -0
- package/dist/index.js +49 -0
- package/dist/sync/bot-detection.js +24 -0
- package/dist/sync/commit-files.js +50 -0
- package/dist/sync/derive-thread-state.js +38 -0
- package/dist/sync/scheduler.js +28 -0
- package/dist/sync/sync-manager.js +150 -0
- package/dist/sync/sync-repo.js +122 -0
- package/dist/sync/upsert.js +528 -0
- package/package.json +46 -0
- package/public/assets/index-6p3C9xk7.css +10 -0
- package/public/assets/index-C-CZcLLq.js +1360 -0
- package/public/index.html +25 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFile, execFileSync } from 'node:child_process';
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
// ── tiny ANSI helpers (degrade gracefully when not a TTY) ──────────────────
|
|
7
|
+
const useColor = process.stdout.isTTY && process.env.NO_COLOR === undefined;
|
|
8
|
+
const paint = (code, s) => useColor ? `[${code}m${s}[0m` : s;
|
|
9
|
+
const cyan = (s) => paint('36', s);
|
|
10
|
+
const dim = (s) => paint('2', s);
|
|
11
|
+
const bold = (s) => paint('1', s);
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const opts = { open: true, help: false };
|
|
14
|
+
for (let i = 0; i < argv.length; i++) {
|
|
15
|
+
const arg = argv[i];
|
|
16
|
+
switch (arg) {
|
|
17
|
+
case '--no-open':
|
|
18
|
+
opts.open = false;
|
|
19
|
+
break;
|
|
20
|
+
case '--port': {
|
|
21
|
+
const v = argv[++i];
|
|
22
|
+
const n = v ? Number.parseInt(v, 10) : NaN;
|
|
23
|
+
if (!Number.isFinite(n)) {
|
|
24
|
+
console.error('--port requires a number');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
opts.port = n;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
case '--db': {
|
|
31
|
+
const v = argv[++i];
|
|
32
|
+
if (!v) {
|
|
33
|
+
console.error('--db requires a path');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
opts.db = v;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case '--help':
|
|
40
|
+
case '-h':
|
|
41
|
+
opts.help = true;
|
|
42
|
+
break;
|
|
43
|
+
default:
|
|
44
|
+
console.error(`Unknown argument: ${arg}`);
|
|
45
|
+
console.error('Run `pierre --help` for usage.');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return opts;
|
|
50
|
+
}
|
|
51
|
+
function printUsage() {
|
|
52
|
+
console.log(`pierre — ${'local-only GitHub PR activity dashboard'}
|
|
53
|
+
|
|
54
|
+
Usage:
|
|
55
|
+
pierre [options]
|
|
56
|
+
pierre-review [options]
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
--no-open Don't open the browser (also honours NO_OPEN env)
|
|
60
|
+
--port <n> Port to listen on (also PORT env, default 4000)
|
|
61
|
+
--db <path> SQLite DB path (also DATABASE_URL env)
|
|
62
|
+
-h, --help Show this help
|
|
63
|
+
|
|
64
|
+
Prerequisite:
|
|
65
|
+
Requires the GitHub CLI (https://cli.github.com), authenticated via
|
|
66
|
+
\`gh auth login\`. The dashboard reads your activity using your gh token.
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
// Cross-platform browser open — no extra dependency.
|
|
70
|
+
function openBrowser(url) {
|
|
71
|
+
const platform = process.platform;
|
|
72
|
+
const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open';
|
|
73
|
+
const args = platform === 'win32' ? ['/c', 'start', '""', url] : [url];
|
|
74
|
+
// Swallow failures — headless / no-DE environments are fine.
|
|
75
|
+
execFile(cmd, args, () => {
|
|
76
|
+
/* ignore */
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async function main() {
|
|
80
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
81
|
+
if (opts.help) {
|
|
82
|
+
printUsage();
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
// ── map flags → env BEFORE importing config/app (config reads these) ──────
|
|
86
|
+
if (opts.port !== undefined)
|
|
87
|
+
process.env.PORT = String(opts.port);
|
|
88
|
+
if (opts.db !== undefined)
|
|
89
|
+
process.env.DATABASE_URL = opts.db;
|
|
90
|
+
if (opts.open === false)
|
|
91
|
+
process.env.NO_OPEN = '1';
|
|
92
|
+
// Production mode: skip pino-pretty (not shipped) and enable static serving.
|
|
93
|
+
process.env.NODE_ENV ??= 'production';
|
|
94
|
+
// ── default the DB to a user-writable home location (mkdir -p) ────────────
|
|
95
|
+
// The package dir is read-only for global installs, so never write there.
|
|
96
|
+
if (!process.env.DATABASE_URL) {
|
|
97
|
+
const dbPath = join(homedir(), '.pierre-review', 'pierre-review.sqlite');
|
|
98
|
+
process.env.DATABASE_URL = dbPath;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
mkdirSync(dirname(process.env.DATABASE_URL), { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
/* best-effort; client.ts also mkdirs */
|
|
105
|
+
}
|
|
106
|
+
// ── pre-check gh auth with a friendly message (contract §6) ───────────────
|
|
107
|
+
try {
|
|
108
|
+
execFileSync('gh', ['auth', 'token'], { stdio: 'ignore' });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
console.error('');
|
|
112
|
+
console.error(bold('GitHub CLI not found or not authenticated.'));
|
|
113
|
+
console.error('Install the GitHub CLI (https://cli.github.com) and run `gh auth login`.');
|
|
114
|
+
console.error('');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const port = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : 4000;
|
|
118
|
+
const url = `http://localhost:${port}`;
|
|
119
|
+
// ── banner ────────────────────────────────────────────────────────────────
|
|
120
|
+
const { PIERRE_ASCII, TAGLINE } = await import('./ascii.js');
|
|
121
|
+
console.log(cyan(PIERRE_ASCII));
|
|
122
|
+
console.log(` ${dim(TAGLINE)}`);
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(` ${cyan('▸')} ${bold(url)}`);
|
|
125
|
+
console.log('');
|
|
126
|
+
// ── boot the server (migrate → user → app → scheduler → listen) ───────────
|
|
127
|
+
const { start } = await import('./index.js');
|
|
128
|
+
await start();
|
|
129
|
+
// ── open the browser once we're listening ─────────────────────────────────
|
|
130
|
+
const skipOpen = opts.open === false || process.env.NO_OPEN !== undefined;
|
|
131
|
+
if (!skipOpen)
|
|
132
|
+
openBrowser(url);
|
|
133
|
+
}
|
|
134
|
+
main().catch((err) => {
|
|
135
|
+
console.error('Failed to start pierre:', err);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
3
|
+
// apps/backend as the base for relative paths regardless of cwd.
|
|
4
|
+
const backendRoot = resolve(import.meta.dirname, '..');
|
|
5
|
+
// Load .env from the repo root and (optionally) apps/backend before reading
|
|
6
|
+
// any config. Node's loader no-ops politely if a file is missing.
|
|
7
|
+
for (const envPath of [
|
|
8
|
+
resolve(backendRoot, '../../.env'),
|
|
9
|
+
resolve(backendRoot, '.env'),
|
|
10
|
+
]) {
|
|
11
|
+
try {
|
|
12
|
+
process.loadEnvFile(envPath);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
/* no .env at this location */
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function intFromEnv(key, fallback) {
|
|
19
|
+
const raw = process.env[key];
|
|
20
|
+
if (!raw)
|
|
21
|
+
return fallback;
|
|
22
|
+
const n = Number.parseInt(raw, 10);
|
|
23
|
+
return Number.isFinite(n) ? n : fallback;
|
|
24
|
+
}
|
|
25
|
+
// Default the SQLite DB to a user-writable location in the home dir so the app
|
|
26
|
+
// works when installed globally (the package dir is read-only). DATABASE_URL /
|
|
27
|
+
// --db override this; a relative override resolves under apps/backend (dev).
|
|
28
|
+
const defaultDbPath = join(homedir(), '.pierre-review', 'pierre-review.sqlite');
|
|
29
|
+
const rawDbUrl = process.env.DATABASE_URL ?? defaultDbPath;
|
|
30
|
+
export const config = {
|
|
31
|
+
port: intFromEnv('PORT', 4000),
|
|
32
|
+
host: process.env.HOST ?? '127.0.0.1',
|
|
33
|
+
dbPath: isAbsolute(rawDbUrl) ? rawDbUrl : resolve(backendRoot, rawDbUrl),
|
|
34
|
+
backfillDays: intFromEnv('BACKFILL_DAYS', 90),
|
|
35
|
+
syncCron: process.env.SYNC_CRON ?? '*/5 * * * *',
|
|
36
|
+
syncOverlapMinutes: intFromEnv('SYNC_OVERLAP_MINUTES', 20),
|
|
37
|
+
stallThresholdDays: intFromEnv('STALL_THRESHOLD_DAYS', 3),
|
|
38
|
+
// Disable the periodic scheduler (used by scripts/tests).
|
|
39
|
+
disableScheduler: process.env.DISABLE_SCHEDULER === 'true',
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { sqlite } from './client.js';
|
|
2
|
+
// One-time / idempotent maintenance run at startup.
|
|
3
|
+
//
|
|
4
|
+
// GitHub wraps inline-only reviews in an empty "commented" review, which the
|
|
5
|
+
// sync used to record as a `review_submitted` event. Those wrappers duplicate
|
|
6
|
+
// the inline `review_comment` markers on the timeline. New syncs no longer emit
|
|
7
|
+
// them (see sync/upsert.ts), but pre-existing rows linger because upserts only
|
|
8
|
+
// update. This removes them; it also catches reviews whose summary body was
|
|
9
|
+
// later cleared on GitHub. Cheap and safe to run every boot.
|
|
10
|
+
export function cleanupRedundantReviewEvents() {
|
|
11
|
+
const res = sqlite
|
|
12
|
+
.prepare(`DELETE FROM events
|
|
13
|
+
WHERE type = 'review_submitted'
|
|
14
|
+
AND ref_table = 'reviews'
|
|
15
|
+
AND ref_id IN (
|
|
16
|
+
SELECT id FROM reviews
|
|
17
|
+
WHERE state = 'commented' AND (body IS NULL OR trim(body) = '')
|
|
18
|
+
)`)
|
|
19
|
+
.run();
|
|
20
|
+
return res.changes;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
5
|
+
import { config } from '../config.js';
|
|
6
|
+
import * as schema from './schema.js';
|
|
7
|
+
mkdirSync(dirname(config.dbPath), { recursive: true });
|
|
8
|
+
export const sqlite = new Database(config.dbPath);
|
|
9
|
+
sqlite.pragma('journal_mode = WAL');
|
|
10
|
+
sqlite.pragma('foreign_keys = ON');
|
|
11
|
+
export const db = drizzle(sqlite, { schema });
|
|
12
|
+
export { schema };
|
|
13
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Applies pending drizzle migrations, then exits. Run via `pnpm db:migrate`.
|
|
2
|
+
import { sqlite } from './client.js';
|
|
3
|
+
import { runMigrations } from './run-migrations.js';
|
|
4
|
+
try {
|
|
5
|
+
runMigrations();
|
|
6
|
+
console.log('Migrations applied.');
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
console.error('Migration failed:', err);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
sqlite.close();
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
CREATE TABLE `commit_files` (
|
|
2
|
+
`sha` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`paths` text NOT NULL,
|
|
4
|
+
`fetched_at` integer DEFAULT (unixepoch()) NOT NULL
|
|
5
|
+
);
|
|
6
|
+
--> statement-breakpoint
|
|
7
|
+
CREATE TABLE `commits` (
|
|
8
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
9
|
+
`sha` text NOT NULL,
|
|
10
|
+
`pr_id` integer NOT NULL,
|
|
11
|
+
`author_id` integer,
|
|
12
|
+
`committer_id` integer,
|
|
13
|
+
`message` text,
|
|
14
|
+
`committed_at` integer NOT NULL,
|
|
15
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
16
|
+
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
|
17
|
+
FOREIGN KEY (`committer_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
18
|
+
);
|
|
19
|
+
--> statement-breakpoint
|
|
20
|
+
CREATE INDEX `commit_pr_idx` ON `commits` (`pr_id`);--> statement-breakpoint
|
|
21
|
+
CREATE UNIQUE INDEX `commit_sha_pr_ux` ON `commits` (`sha`,`pr_id`);--> statement-breakpoint
|
|
22
|
+
CREATE TABLE `events` (
|
|
23
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
24
|
+
`repo_id` integer NOT NULL,
|
|
25
|
+
`actor_id` integer,
|
|
26
|
+
`pr_id` integer,
|
|
27
|
+
`type` text NOT NULL,
|
|
28
|
+
`occurred_at` integer NOT NULL,
|
|
29
|
+
`ref_table` text,
|
|
30
|
+
`ref_id` integer,
|
|
31
|
+
`dedupe_key` text NOT NULL,
|
|
32
|
+
FOREIGN KEY (`repo_id`) REFERENCES `repos`(`id`) ON UPDATE no action ON DELETE no action,
|
|
33
|
+
FOREIGN KEY (`actor_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
|
34
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action
|
|
35
|
+
);
|
|
36
|
+
--> statement-breakpoint
|
|
37
|
+
CREATE UNIQUE INDEX `events_dedupe_key_unique` ON `events` (`dedupe_key`);--> statement-breakpoint
|
|
38
|
+
CREATE INDEX `events_time_idx` ON `events` (`occurred_at`);--> statement-breakpoint
|
|
39
|
+
CREATE INDEX `events_repo_time_idx` ON `events` (`repo_id`,`occurred_at`);--> statement-breakpoint
|
|
40
|
+
CREATE INDEX `events_actor_idx` ON `events` (`actor_id`);--> statement-breakpoint
|
|
41
|
+
CREATE TABLE `pr_comments` (
|
|
42
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
43
|
+
`github_node_id` text NOT NULL,
|
|
44
|
+
`pr_id` integer NOT NULL,
|
|
45
|
+
`author_id` integer,
|
|
46
|
+
`body` text NOT NULL,
|
|
47
|
+
`created_at` integer NOT NULL,
|
|
48
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
49
|
+
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
50
|
+
);
|
|
51
|
+
--> statement-breakpoint
|
|
52
|
+
CREATE UNIQUE INDEX `pr_comments_github_node_id_unique` ON `pr_comments` (`github_node_id`);--> statement-breakpoint
|
|
53
|
+
CREATE INDEX `prc_pr_idx` ON `pr_comments` (`pr_id`);--> statement-breakpoint
|
|
54
|
+
CREATE TABLE `pull_requests` (
|
|
55
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
56
|
+
`github_node_id` text NOT NULL,
|
|
57
|
+
`repo_id` integer NOT NULL,
|
|
58
|
+
`number` integer NOT NULL,
|
|
59
|
+
`title` text NOT NULL,
|
|
60
|
+
`body` text,
|
|
61
|
+
`author_id` integer,
|
|
62
|
+
`state` text NOT NULL,
|
|
63
|
+
`is_draft` integer DEFAULT false NOT NULL,
|
|
64
|
+
`opened_at` integer NOT NULL,
|
|
65
|
+
`first_review_at` integer,
|
|
66
|
+
`last_commit_at` integer,
|
|
67
|
+
`merged_at` integer,
|
|
68
|
+
`closed_at` integer,
|
|
69
|
+
`updated_at` integer NOT NULL,
|
|
70
|
+
FOREIGN KEY (`repo_id`) REFERENCES `repos`(`id`) ON UPDATE no action ON DELETE no action,
|
|
71
|
+
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
72
|
+
);
|
|
73
|
+
--> statement-breakpoint
|
|
74
|
+
CREATE UNIQUE INDEX `pull_requests_github_node_id_unique` ON `pull_requests` (`github_node_id`);--> statement-breakpoint
|
|
75
|
+
CREATE INDEX `pr_repo_idx` ON `pull_requests` (`repo_id`);--> statement-breakpoint
|
|
76
|
+
CREATE INDEX `pr_opened_idx` ON `pull_requests` (`opened_at`);--> statement-breakpoint
|
|
77
|
+
CREATE TABLE `repos` (
|
|
78
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
79
|
+
`owner` text NOT NULL,
|
|
80
|
+
`name` text NOT NULL,
|
|
81
|
+
`github_node_id` text NOT NULL,
|
|
82
|
+
`backfill_until` integer,
|
|
83
|
+
`created_at` integer DEFAULT (unixepoch()) NOT NULL
|
|
84
|
+
);
|
|
85
|
+
--> statement-breakpoint
|
|
86
|
+
CREATE UNIQUE INDEX `repos_github_node_id_unique` ON `repos` (`github_node_id`);--> statement-breakpoint
|
|
87
|
+
CREATE UNIQUE INDEX `repos_owner_name` ON `repos` (`owner`,`name`);--> statement-breakpoint
|
|
88
|
+
CREATE TABLE `review_comments` (
|
|
89
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
90
|
+
`github_node_id` text NOT NULL,
|
|
91
|
+
`thread_id` integer NOT NULL,
|
|
92
|
+
`pr_id` integer NOT NULL,
|
|
93
|
+
`author_id` integer,
|
|
94
|
+
`body` text NOT NULL,
|
|
95
|
+
`diff_hunk` text,
|
|
96
|
+
`created_at` integer NOT NULL,
|
|
97
|
+
FOREIGN KEY (`thread_id`) REFERENCES `review_threads`(`id`) ON UPDATE no action ON DELETE no action,
|
|
98
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
99
|
+
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
100
|
+
);
|
|
101
|
+
--> statement-breakpoint
|
|
102
|
+
CREATE UNIQUE INDEX `review_comments_github_node_id_unique` ON `review_comments` (`github_node_id`);--> statement-breakpoint
|
|
103
|
+
CREATE INDEX `rc_thread_idx` ON `review_comments` (`thread_id`);--> statement-breakpoint
|
|
104
|
+
CREATE TABLE `review_threads` (
|
|
105
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
106
|
+
`github_node_id` text NOT NULL,
|
|
107
|
+
`pr_id` integer NOT NULL,
|
|
108
|
+
`path` text NOT NULL,
|
|
109
|
+
`line` integer,
|
|
110
|
+
`is_resolved` integer NOT NULL,
|
|
111
|
+
`is_outdated` integer DEFAULT false NOT NULL,
|
|
112
|
+
`derived_state` text NOT NULL,
|
|
113
|
+
`original_commenter_id` integer,
|
|
114
|
+
`created_at` integer NOT NULL,
|
|
115
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
116
|
+
FOREIGN KEY (`original_commenter_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
117
|
+
);
|
|
118
|
+
--> statement-breakpoint
|
|
119
|
+
CREATE UNIQUE INDEX `review_threads_github_node_id_unique` ON `review_threads` (`github_node_id`);--> statement-breakpoint
|
|
120
|
+
CREATE INDEX `thread_pr_idx` ON `review_threads` (`pr_id`);--> statement-breakpoint
|
|
121
|
+
CREATE TABLE `reviews` (
|
|
122
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
123
|
+
`github_node_id` text NOT NULL,
|
|
124
|
+
`pr_id` integer NOT NULL,
|
|
125
|
+
`author_id` integer,
|
|
126
|
+
`state` text NOT NULL,
|
|
127
|
+
`body` text,
|
|
128
|
+
`submitted_at` integer NOT NULL,
|
|
129
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
130
|
+
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
131
|
+
);
|
|
132
|
+
--> statement-breakpoint
|
|
133
|
+
CREATE UNIQUE INDEX `reviews_github_node_id_unique` ON `reviews` (`github_node_id`);--> statement-breakpoint
|
|
134
|
+
CREATE INDEX `rv_pr_idx` ON `reviews` (`pr_id`);--> statement-breakpoint
|
|
135
|
+
CREATE TABLE `sync_state` (
|
|
136
|
+
`repo_id` integer PRIMARY KEY NOT NULL,
|
|
137
|
+
`last_full_sync_at` integer,
|
|
138
|
+
`last_incremental_sync_at` integer,
|
|
139
|
+
`last_sync_status` text,
|
|
140
|
+
`last_sync_error` text,
|
|
141
|
+
FOREIGN KEY (`repo_id`) REFERENCES `repos`(`id`) ON UPDATE no action ON DELETE no action
|
|
142
|
+
);
|
|
143
|
+
--> statement-breakpoint
|
|
144
|
+
CREATE TABLE `users` (
|
|
145
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
146
|
+
`github_login` text NOT NULL,
|
|
147
|
+
`github_node_id` text,
|
|
148
|
+
`display_name` text,
|
|
149
|
+
`avatar_url` text,
|
|
150
|
+
`is_bot` integer DEFAULT false NOT NULL,
|
|
151
|
+
`is_bot_overridden` integer DEFAULT false NOT NULL
|
|
152
|
+
);
|
|
153
|
+
--> statement-breakpoint
|
|
154
|
+
CREATE UNIQUE INDEX `users_github_login_unique` ON `users` (`github_login`);--> statement-breakpoint
|
|
155
|
+
CREATE UNIQUE INDEX `users_github_node_id_unique` ON `users` (`github_node_id`);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
CREATE TABLE `local_user` (
|
|
2
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
3
|
+
`github_login` text NOT NULL,
|
|
4
|
+
`github_id` text NOT NULL,
|
|
5
|
+
`avatar_url` text,
|
|
6
|
+
`cached_at` integer NOT NULL
|
|
7
|
+
);
|
|
8
|
+
--> statement-breakpoint
|
|
9
|
+
CREATE TABLE `pr_views` (
|
|
10
|
+
`pr_id` integer PRIMARY KEY NOT NULL,
|
|
11
|
+
`last_viewed_sha` text,
|
|
12
|
+
`last_viewed_at` integer NOT NULL,
|
|
13
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action
|
|
14
|
+
);
|
|
15
|
+
--> statement-breakpoint
|
|
16
|
+
CREATE TABLE `review_requests` (
|
|
17
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
18
|
+
`pr_id` integer NOT NULL,
|
|
19
|
+
`user_id` integer,
|
|
20
|
+
`team_name` text,
|
|
21
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
|
22
|
+
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
23
|
+
);
|
|
24
|
+
--> statement-breakpoint
|
|
25
|
+
CREATE INDEX `rr_pr_idx` ON `review_requests` (`pr_id`);--> statement-breakpoint
|
|
26
|
+
CREATE INDEX `rr_user_idx` ON `review_requests` (`user_id`);--> statement-breakpoint
|
|
27
|
+
ALTER TABLE `pull_requests` ADD `head_sha` text;--> statement-breakpoint
|
|
28
|
+
ALTER TABLE `pull_requests` ADD `ci_status` text;--> statement-breakpoint
|
|
29
|
+
ALTER TABLE `pull_requests` ADD `mergeable` text;--> statement-breakpoint
|
|
30
|
+
ALTER TABLE `pull_requests` ADD `merge_state_status` text;--> statement-breakpoint
|
|
31
|
+
ALTER TABLE `pull_requests` ADD `labels` text;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE `my_turn_dismissals` (
|
|
2
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
3
|
+
`kind` text NOT NULL,
|
|
4
|
+
`ref_id` integer NOT NULL,
|
|
5
|
+
`dismissed_at` integer NOT NULL
|
|
6
|
+
);
|
|
7
|
+
--> statement-breakpoint
|
|
8
|
+
CREATE UNIQUE INDEX `mtd_kind_ref_ux` ON `my_turn_dismissals` (`kind`,`ref_id`);--> statement-breakpoint
|
|
9
|
+
ALTER TABLE `pull_requests` ADD `check_runs` text;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE `pull_requests` ADD `merged_by_id` integer REFERENCES users(id);
|