This commit is contained in:
parent
b455647580
commit
816881c2cc
10 changed files with 654 additions and 6 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, test } from "bun:test";
|
||||
import { buildDiscordPayload, notifyDiscord, parseDiscordConfig } from "../src/discord";
|
||||
import type { GitWebhookEvent } from "../src/types";
|
||||
import type { FeedSignal, GitWebhookEvent } from "../src/types";
|
||||
|
||||
const pushEvent: GitWebhookEvent = {
|
||||
provider: "jojo",
|
||||
|
|
@ -25,6 +25,33 @@ const pushEvent: GitWebhookEvent = {
|
|||
},
|
||||
};
|
||||
|
||||
const feedSignal: FeedSignal = {
|
||||
sourceId: "github-openai-codex-main",
|
||||
provider: "github",
|
||||
event: "push",
|
||||
entryId: "tag:github.com,2008:Grit::Commit/0123456789abcdef0123456789abcdef01234567",
|
||||
title: "Tighten sandbox setup",
|
||||
url: "https://github.com/openai/codex/commit/0123456789abcdef0123456789abcdef01234567",
|
||||
author: "bookholt-oai",
|
||||
publishedAt: "2026-05-12T21:00:00.000Z",
|
||||
repo: {
|
||||
owner: "openai",
|
||||
name: "codex",
|
||||
fullName: "openai/codex",
|
||||
webUrl: "https://github.com/openai/codex",
|
||||
defaultBranch: "main",
|
||||
},
|
||||
ref: "refs/heads/main",
|
||||
sha: "0123456789abcdef0123456789abcdef01234567",
|
||||
target: {
|
||||
provider: "github",
|
||||
repoFullName: "peezy-tech/codex",
|
||||
branch: "main",
|
||||
mode: "notify_only",
|
||||
},
|
||||
raw: {},
|
||||
};
|
||||
|
||||
describe("discord notifications", () => {
|
||||
test("parses default notify events", () => {
|
||||
const config = parseDiscordConfig({});
|
||||
|
|
@ -55,6 +82,14 @@ describe("discord notifications", () => {
|
|||
expect(payload.embeds[0].fields).toContainEqual({ name: "Queued", value: "main_push", inline: true });
|
||||
});
|
||||
|
||||
test("builds readable feed embeds", () => {
|
||||
const payload = buildDiscordPayload({ signal: feedSignal });
|
||||
expect(payload.embeds[0].title).toBe("[github] openai/codex upstream update on main");
|
||||
expect(payload.embeds[0].description).toBe("Tighten sandbox setup");
|
||||
expect(payload.embeds[0].url).toBe("https://github.com/openai/codex/commit/0123456789abcdef0123456789abcdef01234567");
|
||||
expect(payload.embeds[0].footer.text).toBe("feed watcher");
|
||||
});
|
||||
|
||||
test("does nothing without a webhook URL", async () => {
|
||||
let calls = 0;
|
||||
await notifyDiscord(parseDiscordConfig({}), { event: pushEvent }, async () => {
|
||||
|
|
|
|||
140
test/feed.test.ts
Normal file
140
test/feed.test.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { mkdtemp, readFile, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { loadSources, parseFeedEntries, pollFeedsOnce, signalFromEntry } from "../src/feed";
|
||||
import type { FeedSourceConfig } from "../src/types";
|
||||
|
||||
const atom = `<?xml version="1.0"?>
|
||||
<feed>
|
||||
<entry>
|
||||
<id>tag:github.com,2008:Grit::Commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</id>
|
||||
<link type="text/html" rel="alternate" href="https://github.com/openai/codex/commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"/>
|
||||
<title>Update main</title>
|
||||
<updated>2026-05-12T10:00:00Z</updated>
|
||||
<author><name>alice</name></author>
|
||||
</entry>
|
||||
<entry>
|
||||
<id>tag:github.com,2008:Grit::Commit/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</id>
|
||||
<link type="text/html" rel="alternate" href="https://github.com/openai/codex/commit/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"/>
|
||||
<title>Older update</title>
|
||||
<updated>2026-05-12T09:00:00Z</updated>
|
||||
<author><name>bob</name></author>
|
||||
</entry>
|
||||
</feed>`;
|
||||
|
||||
const rss = `<?xml version="1.0"?>
|
||||
<rss><channel>
|
||||
<item>
|
||||
<title>v1.2.3</title>
|
||||
<link>https://codeberg.org/forgejo/forgejo/releases/tag/v1.2.3</link>
|
||||
<guid>release-123</guid>
|
||||
<author>release-team</author>
|
||||
<pubDate>Tue, 12 May 2026 10:00:00 +0000</pubDate>
|
||||
</item>
|
||||
</channel></rss>`;
|
||||
|
||||
const source: FeedSourceConfig = {
|
||||
id: "github-openai-codex-main",
|
||||
provider: "github",
|
||||
url: "https://github.com/openai/codex/commits/main.atom",
|
||||
event: "push",
|
||||
repo: {
|
||||
owner: "openai",
|
||||
name: "codex",
|
||||
fullName: "openai/codex",
|
||||
webUrl: "https://github.com/openai/codex",
|
||||
defaultBranch: "main",
|
||||
},
|
||||
target: {
|
||||
provider: "github",
|
||||
repoFullName: "peezy-tech/codex",
|
||||
branch: "main",
|
||||
mode: "notify_only",
|
||||
},
|
||||
};
|
||||
|
||||
describe("feed watcher", () => {
|
||||
test("parses Atom and RSS feed entries", () => {
|
||||
expect(parseFeedEntries(atom)[0]).toMatchObject({
|
||||
title: "Update main",
|
||||
author: "alice",
|
||||
url: "https://github.com/openai/codex/commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
});
|
||||
expect(parseFeedEntries(rss)[0]).toMatchObject({
|
||||
id: "release-123",
|
||||
title: "v1.2.3",
|
||||
author: "release-team",
|
||||
});
|
||||
});
|
||||
|
||||
test("normalizes commit feed entries into push signals", () => {
|
||||
const signal = signalFromEntry(source, parseFeedEntries(atom)[0]);
|
||||
expect(signal).toMatchObject({
|
||||
sourceId: "github-openai-codex-main",
|
||||
provider: "github",
|
||||
event: "push",
|
||||
ref: "refs/heads/main",
|
||||
sha: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
repo: { fullName: "openai/codex" },
|
||||
});
|
||||
});
|
||||
|
||||
test("loads configured feed sources", async () => {
|
||||
const sources = await loadSources(join(import.meta.dir, "..", "feed-sources.json"));
|
||||
expect(sources.map((item) => item.id)).toEqual([
|
||||
"codeberg-forgejo-branch",
|
||||
"codeberg-forgejo-releases",
|
||||
"github-openai-codex-main",
|
||||
"github-openai-codex-releases",
|
||||
]);
|
||||
});
|
||||
|
||||
test("first poll primes state without emitting old entries", async () => {
|
||||
const dataDir = await mkdtemp(join(tmpdir(), "git-webhooks-feed-"));
|
||||
const sourcesPath = join(dataDir, "sources.json");
|
||||
await writeFile(sourcesPath, JSON.stringify({ sources: [source] }), "utf8");
|
||||
|
||||
await pollFeedsOnce({ dataDir, sourcesPath, discord: { webhookUrl: "https://discord.example/webhook", notifyEvents: new Set(["push"]) } }, async () => {
|
||||
return new Response(atom, { status: 200 });
|
||||
});
|
||||
|
||||
const state = JSON.parse(await readFile(join(dataDir, "feed-state.json"), "utf8"));
|
||||
expect(state["github-openai-codex-main"].lastSeenId).toBe("tag:github.com,2008:Grit::Commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
||||
await expect(readFile(join(dataDir, "feed-events.jsonl"), "utf8")).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("later polls emit new entries and release fork sync jobs", async () => {
|
||||
const dataDir = await mkdtemp(join(tmpdir(), "git-webhooks-feed-"));
|
||||
const sourcesPath = join(dataDir, "sources.json");
|
||||
const releaseSource: FeedSourceConfig = {
|
||||
...source,
|
||||
id: "github-openai-codex-releases",
|
||||
url: "https://github.com/openai/codex/releases.atom",
|
||||
event: "release",
|
||||
target: {
|
||||
provider: "github",
|
||||
repoFullName: "peezy-tech/codex",
|
||||
branch: "main",
|
||||
mode: "fork_sync",
|
||||
},
|
||||
};
|
||||
await writeFile(sourcesPath, JSON.stringify({ sources: [releaseSource] }), "utf8");
|
||||
await writeFile(join(dataDir, "feed-state.json"), JSON.stringify({
|
||||
"github-openai-codex-releases": {
|
||||
lastSeenId: "older-release",
|
||||
lastCheckedAt: "2026-05-12T09:00:00.000Z",
|
||||
},
|
||||
}), "utf8");
|
||||
|
||||
let feedCalls = 0;
|
||||
await pollFeedsOnce({ dataDir, sourcesPath, discord: { notifyEvents: new Set(["release"]) } }, async () => {
|
||||
feedCalls += 1;
|
||||
return new Response(rss, { status: 200 });
|
||||
});
|
||||
|
||||
expect(await readFile(join(dataDir, "feed-events.jsonl"), "utf8")).toContain("\"event\":\"release\"");
|
||||
expect(await readFile(join(dataDir, "feed-jobs.jsonl"), "utf8")).toContain("\"kind\":\"fork_sync\"");
|
||||
expect(feedCalls).toBe(1);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue