Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SLACK_BOT_TOKEN=xoxb-
SLACK_APP_TOKEN=xapp-
GITHUB_TOKEN=github_pat_
DATABASE_URL=postgres://root:password@localhost:5432/app
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Drizzle internal state - never hand-edited
drizzle/meta/*.json linguist-generated=true
6 changes: 6 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

set -e
set -o pipefail

bun run lint
18 changes: 18 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Test

on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize]

concurrency:
group: ${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Tests
uses: ./.github/workflows/test.yml
secrets: inherit
61 changes: 61 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Release

on:
workflow_dispatch:
inputs:
bump:
description: "Version bump"
type: choice
required: true
default: patch
options:
- major
- minor
- patch
- prerelease

env:
DOCKER_IMAGE: ghcr.io/${{ github.repository }}

jobs:
test:
uses: ./.github/workflows/test.yml
secrets: inherit

release:
needs: test
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: oven-sh/setup-bun@v2
- uses: aboutbits/github-actions-base/git-setup@v2
with:
user-name: github-actions[bot]
user-email: github-actions[bot]@users.noreply.github.com
- name: Bump version in package.json
id: version
run: |
bun pm version ${{ github.event.inputs.bump }} --no-git-tag-version
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
- uses: aboutbits/github-actions-docker/build-push@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
docker-image: ${{ env.DOCKER_IMAGE }}
docker-tag: ${{ steps.version.outputs.version }}
platforms: linux/amd64,linux/arm64
- uses: aboutbits/github-actions-base/git-commit-and-push-all@v2
with:
message: ${{ steps.version.outputs.version }}
- uses: aboutbits/github-actions-base/git-create-or-update-tag@v2
with:
tag-name: v${{ steps.version.outputs.version }}
- uses: aboutbits/github-actions-base/github-create-release@v2
with:
tag-name: v${{ steps.version.outputs.version }}
22 changes: 22 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Lint and Test

on:
workflow_call:

jobs:
test:
name: Lint and Test
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- name: Configure GitHub Packages registry
run: |
echo "@aboutbits:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Lint
run: bun run lint
- name: Test
run: bun test
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# dependencies (bun install)
node_modules

# output
out
dist
*.tgz

# code coverage
coverage
*.lcov

# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# dotenv environment variable files
.env
.npmrc
.env.development.local
.env.test.local
.env.production.local
.env.local

# caches
.eslintcache
.cache
*.tsbuildinfo

# IntelliJ based IDEs
.idea

# Finder (MacOS) folder config
.DS_Store
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM oven/bun:alpine AS deps
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production

FROM oven/bun:alpine AS runner
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY tsconfig.json ./
COPY src/ ./src/
COPY drizzle/ ./drizzle/

# Non root user
USER bun

CMD ["bun", "run", "src/index.ts"]
1,804 changes: 1,804 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
db:
image: postgres:18
environment:
POSTGRES_DB: app
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
14 changes: 14 additions & 0 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from 'drizzle-kit';
import { DB_SCHEMA } from '@db/schema.ts';

export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
migrations: {
schema: DB_SCHEMA,
},
})
53 changes: 53 additions & 0 deletions drizzle/0000_curious_viper.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
CREATE TABLE "main"."notifications" (
"id" bigserial PRIMARY KEY NOT NULL,
"release_id" bigint NOT NULL,
"channel_id" text NOT NULL,
"kind" text NOT NULL,
"sent_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "notifications_release_id_channel_id_unique" UNIQUE("release_id","channel_id")
);
--> statement-breakpoint
CREATE TABLE "main"."releases" (
"id" bigserial PRIMARY KEY NOT NULL,
"repository_id" bigint NOT NULL,
"forge_release_id" text NOT NULL,
"tag_name" text NOT NULL,
"name" text,
"url" text NOT NULL,
"published_at" timestamp with time zone NOT NULL,
"is_security" boolean DEFAULT false NOT NULL,
"security_score" integer,
"security_reasons" jsonb,
"discovered_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "releases_repository_id_forge_release_id_unique" UNIQUE("repository_id","forge_release_id")
);
--> statement-breakpoint
CREATE TABLE "main"."repositories" (
"id" bigserial PRIMARY KEY NOT NULL,
"forge" text NOT NULL,
"owner" text NOT NULL,
"repo" text NOT NULL,
"url" text,
"last_checked_at" timestamp with time zone,
"poll_token" text,
"last_known_release_id" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "repositories_forge_owner_repo_unique" UNIQUE("forge","owner","repo")
);
--> statement-breakpoint
CREATE TABLE "main"."subscriptions" (
"id" bigserial PRIMARY KEY NOT NULL,
"channel_id" text NOT NULL,
"repository_id" bigint NOT NULL,
"subscribed_at" timestamp with time zone DEFAULT now() NOT NULL,
"subscribed_by" text NOT NULL,
"notification_mode" text NOT NULL,
CONSTRAINT "subscriptions_channel_id_repository_id_unique" UNIQUE("channel_id","repository_id")
);
--> statement-breakpoint
ALTER TABLE "main"."notifications" ADD CONSTRAINT "notifications_release_id_releases_id_fk" FOREIGN KEY ("release_id") REFERENCES "main"."releases"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "main"."releases" ADD CONSTRAINT "releases_repository_id_repositories_id_fk" FOREIGN KEY ("repository_id") REFERENCES "main"."repositories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "main"."subscriptions" ADD CONSTRAINT "subscriptions_repository_id_repositories_id_fk" FOREIGN KEY ("repository_id") REFERENCES "main"."repositories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "idx_notifications_channel_id" ON "main"."notifications" USING btree ("channel_id");--> statement-breakpoint
CREATE INDEX "idx_releases_repository_id_published_at" ON "main"."releases" USING btree ("repository_id","published_at" DESC);--> statement-breakpoint
CREATE INDEX "idx_subscriptions_repository_id" ON "main"."subscriptions" USING btree ("repository_id");
Loading