18 Commits

Author SHA1 Message Date
2587483733 bump: v0.0.31 -> v0.0.32
Some checks failed
Check / check (push) Has been skipped
Release / check (push) Successful in 1m32s
Release / release (push) Failing after 1m49s
Release / package (push) Has been skipped
2025-05-16 17:57:30 -04:00
575ec574dd fix: add dot to build
All checks were successful
Check / check (push) Successful in 52s
2025-05-16 17:55:48 -04:00
815cf96374 bump: v0.0.30 -> v0.0.31
Some checks failed
Check / check (push) Has been skipped
Release / check (push) Successful in 1m32s
Release / release (push) Successful in 1m47s
Release / package (push) Failing after 5s
2025-05-16 17:34:54 -04:00
2b6c24bc86 fix: remove label, as it should be generated by docker/metadata-action
All checks were successful
Check / check (push) Successful in 52s
2025-05-16 17:32:37 -04:00
632774d051 style: rename github to gitea for gitea actions
All checks were successful
Check / check (push) Successful in 52s
2025-05-16 17:27:53 -04:00
1d6b419a15 fix: git automerge
All checks were successful
Check / check (push) Successful in 52s
2025-05-16 15:04:39 -04:00
2da7526265 fix: switch the protobuf extension
All checks were successful
Check / check (push) Successful in 52s
2025-05-16 14:58:43 -04:00
92877b669e fix: remove renovate, it doesn't support nix well
All checks were successful
Check / check (push) Successful in 51s
2025-05-14 12:15:17 -04:00
10168843e1 fix: specify renovate repos
All checks were successful
Check / check (push) Successful in 51s
2025-05-14 11:48:30 -04:00
0889f9c7b1 fix: autodiscover
All checks were successful
Check / check (push) Successful in 51s
2025-05-14 11:40:11 -04:00
084010e38c feat: renovate
All checks were successful
Check / check (push) Successful in 51s
2025-05-14 11:36:54 -04:00
8158c195f5 fix: delete branch after merge
All checks were successful
Check / check (push) Successful in 50s
2025-05-14 10:35:30 -04:00
174d15de5b fix: merge when checks succeed
All checks were successful
Check / check (push) Successful in 51s
2025-05-14 10:02:08 -04:00
56523795d5 fix: force the push
All checks were successful
Check / check (push) Successful in 50s
2025-05-14 09:17:28 -04:00
32bdb3d709 fix: actually fetch
All checks were successful
Check / check (push) Successful in 1m6s
2025-05-14 08:47:46 -04:00
b30d14af9a fix: push to new pr
All checks were successful
Check / check (push) Successful in 52s
2025-05-14 08:24:33 -04:00
1220a37b60 fix: use gitea api
All checks were successful
Check / check (push) Successful in 52s
2025-05-14 08:08:13 -04:00
a3e008c317 fix: create gitea pr
All checks were successful
Check / check (push) Successful in 49s
2025-05-14 07:44:11 -04:00
15 changed files with 111 additions and 48 deletions

View File

@ -12,8 +12,8 @@ jobs:
name: check name: check
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: | if: |
contains(github.event.head_commit.message, 'bump:') == false && contains(gitea.event.head_commit.message, 'bump:') == false &&
contains(github.event.head_commit.message, 'Merge pull request') == false contains(gitea.event.head_commit.message, 'Merge pull request') == false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4

View File

@ -47,12 +47,12 @@ jobs:
- name: Build - name: Build
run: > run: >
nix build nix build
.#trevstack-linux-amd64 .#trevstack-linux-amd64
.#trevstack-linux-arm64 .#trevstack-linux-arm64
.#trevstack-linux-arm .#trevstack-linux-arm
.#trevstack-windows-amd64 .#trevstack-windows-amd64
.#trevstack-darwin-amd64 .#trevstack-darwin-amd64
.#trevstack-darwin-arm64 .#trevstack-darwin-arm64
- name: Release - name: Release
uses: akkuman/gitea-release-action@v1 uses: akkuman/gitea-release-action@v1
@ -71,7 +71,7 @@ jobs:
with: with:
# list of Docker images to use as base name for tags # list of Docker images to use as base name for tags
images: | images: |
${{ vars.URL }}/${{ github.repository }} ${{ gitea.server_url }}/${{ gitea.repository }}
# generate Docker tags based on the following events/attributes # generate Docker tags based on the following events/attributes
tags: | tags: |
type=ref,event=branch type=ref,event=branch
@ -80,9 +80,9 @@ jobs:
- name: Login to Gitea Container Registry - name: Login to Gitea Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ vars.URL }} registry: ${{ gitea.server_url }}
username: ${{ vars.USERNAME }} username: ${{ gitea.actor }}
password: ${{ secrets.PASSWORD }} password: ${{ secrets.PAT }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3

View File

@ -11,6 +11,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v31 uses: cachix/install-nix-action@v31
@ -28,12 +30,33 @@ jobs:
run: | run: |
git config user.name "github-actions[bot]" git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B update
- name: Update - name: Update
run: nix run .#update run: nix run .#update
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v7 env:
with: PAT: ${{ secrets.PAT }}
title: update run: |
body: automatic update URL="${{ gitea.server_url }}"
REPO_OWNER_SLASH_NAME="${{ gitea.repository }}"
if ! git ls-remote --exit-code origin update; then
git push origin update --force
PR_RESPONSE=$(curl -s -X POST -H "Authorization: token $PAT" \
-H "Content-Type: application/json" \
-d '{"title":"update","body":"automatic update","head":"update","base":"main"}' \
"https://$URL/api/v1/repos/$REPO_OWNER_SLASH_NAME/pulls")
PR_NUMBER=$(echo "$PR_RESPONSE" | jq -r '.number')
curl -s -X POST -H "Authorization: token $PAT" \
-H "Content-Type: application/json" \
-d '{"Do":"merge","merge_when_checks_succeed":true,"delete_branch_after_merge":true}' \
"https://$URL/api/v1/repos/$REPO_OWNER_SLASH_NAME/pulls/$PR_NUMBER/merge"
else
git push origin update --force
fi

View File

@ -51,12 +51,12 @@ jobs:
- name: Build - name: Build
run: > run: >
nix build nix build
.#trevstack-linux-amd64 .#trevstack-linux-amd64
.#trevstack-linux-arm64 .#trevstack-linux-arm64
.#trevstack-linux-arm .#trevstack-linux-arm
.#trevstack-windows-amd64 .#trevstack-windows-amd64
.#trevstack-darwin-amd64 .#trevstack-darwin-amd64
.#trevstack-darwin-arm64 .#trevstack-darwin-arm64
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
@ -76,19 +76,12 @@ jobs:
with: with:
# list of Docker images to use as base name for tags # list of Docker images to use as base name for tags
images: | images: |
${{ github.repository }}
ghcr.io/${{ github.repository }} ghcr.io/${{ github.repository }}
# generate Docker tags based on the following events/attributes # generate Docker tags based on the following events/attributes
tags: | tags: |
type=ref,event=branch type=ref,event=branch
type=semver,pattern={{version}} type=semver,pattern={{version}}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:

View File

@ -37,12 +37,14 @@ jobs:
run: nix run .#update run: nix run .#update
- name: Create Pull Request - name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v7
with: with:
branch: update
title: update title: update
body: automatic update body: automatic update
- name: Enable Automerge - name: Enable Automerge
run: gh pr merge --merge --auto "1" run: gh pr merge --merge --auto "${{ steps.cpr.outputs.pull-request-number }}"
env: env:
GH_TOKEN: ${{ secrets.PAT }} GH_TOKEN: ${{ secrets.PAT }}

View File

@ -2,7 +2,7 @@
"recommendations": [ "recommendations": [
"golang.go", "golang.go",
"dorzey.vscode-sqlfluff", "dorzey.vscode-sqlfluff",
"zxh404.vscode-proto3", "bufbuild.vscode-buf",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"svelte.svelte-vscode", "svelte.svelte-vscode",
"esbenp.prettier-vscode" "esbenp.prettier-vscode"

View File

@ -18,8 +18,8 @@
}, },
// Proto // Proto
"[proto3]": { "[proto]": {
"editor.defaultFormatter": "zxh404.vscode-proto3" "editor.defaultFormatter": "bufbuild.vscode-buf"
}, },
// ESLint // ESLint

View File

@ -26,4 +26,5 @@ WORKDIR /app
# Copy /nix/store # Copy /nix/store
COPY --from=builder /tmp/nix-store-closure /nix/store COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /app COPY --from=builder /tmp/build/result /app
CMD ["/app/bin/trevstack"] CMD ["/app/bin/trevstack"]

View File

@ -7,6 +7,7 @@ This is a CRUD app to use as a template for starting projects
- **Communicate anywhere**. Define a [protocol buffer](https://protobuf.dev/), and [Connect](https://connectrpc.com/) generates type-safe code to facilitate communication between the server and any client (web, mobile, embedded, etc). The protocol buffers can contain annotations to validate fields on the client and server. For clients that cannot use Connect, an OpenAPI spec is also generated - **Communicate anywhere**. Define a [protocol buffer](https://protobuf.dev/), and [Connect](https://connectrpc.com/) generates type-safe code to facilitate communication between the server and any client (web, mobile, embedded, etc). The protocol buffers can contain annotations to validate fields on the client and server. For clients that cannot use Connect, an OpenAPI spec is also generated
- **Build anywhere**. The dev environment, testing and building is all declared in a single [Nix](https://nixos.org/) flake. Every developer and server can use the same environment - **Build anywhere**. The dev environment, testing and building is all declared in a single [Nix](https://nixos.org/) flake. Every developer and server can use the same environment
- **Deploy anywhere**. CI/CD is already set up using github actions. New versions are automatically released for every major platform, along with a docker image. The binaries created require zero run-time dependencies and are relatively small (this app is 26 MiB) - **Deploy anywhere**. CI/CD is already set up using github actions. New versions are automatically released for every major platform, along with a docker image. The binaries created require zero run-time dependencies and are relatively small (this app is 26 MiB)
- Can be entirely self-hosted
- Authentication is rolled in, including API key, fingerprint & passkey - Authentication is rolled in, including API key, fingerprint & passkey
- Automatic database migration on startup - Automatic database migration on startup
- Light & dark modes with the [catppuccin](https://catppuccin.com/palette/) color palette - Light & dark modes with the [catppuccin](https://catppuccin.com/palette/) color palette
@ -27,7 +28,7 @@ URL=http://localhost:5173
DATABASE_URL=sqlite:/home/trev/.config/trevstack/sqlite.db DATABASE_URL=sqlite:/home/trev/.config/trevstack/sqlite.db
``` ```
4. Run `treli` 4. Run `treli` to start the server & client
It's that simple. If you're feeling fancy, install [direnv](https://direnv.net/) and the dev environment will load automatically. It's that simple. If you're feeling fancy, install [direnv](https://direnv.net/) and the dev environment will load automatically.
@ -37,11 +38,52 @@ It's that simple. If you're feeling fancy, install [direnv](https://direnv.net/)
- `nix run #bump [major | minor]`: bumps the current version up one. Defaults to "patch" (0.0.1 -> 0.0.2) - `nix run #bump [major | minor]`: bumps the current version up one. Defaults to "patch" (0.0.1 -> 0.0.2)
- `buf lint` & `buf generate`: Lints and generates code from protocol buffers - `nix build [#trevstack-(GOOS)-(GOARCH)]`: builds the application. Defaults to building for your current platform, but can be built to many by specifying the GOOS and GOARCH values
- `sqlc vet` & `sqlc generate`: Verifies and generates code from SQL files - `nix flake check`: runs all validations
- `dbmate new` & `dbmate up`: Creates a new migration file and runs pending migrations - `buf lint` & `buf generate`: lints and generates code from protocol buffers
- `sqlc vet` & `sqlc generate`: verifies and generates code from SQL files
- `dbmate new` & `dbmate up`: creates a new migration file and runs pending migrations
### Github Actions
To use github actions for CI/CD, you'll need to create a fine-grained personal access token for the repository with the permissions:
- Contents (read and write)
- Pull requests (read and write)
And change some settings for the repository:
- General -> Allow auto-merge: true
- Rules -> Rulesets -> New ruleset
- Branch targeting criteria: Default
- Branch rules
- Require status checks to pass -> Add checks -> "check"
- Actions -> General -> Workflow permissions
- Read and write permissions: true
- Allow GitHub Actions to create and approve pull requests: true
- Secrets and variables -> Actions -> Repository secrets
- PAT: (personal access token)
### Gitea Actions
To use gitea actions for CI/CD, you'll need to create an [API token](https://docs.gitea.com/development/api-usage) with the scopes:
- write:repository
- write:package
And change some settings for the repository:
- Repository -> Delete pull request branch after merge by default: true
- Branches -> Add New Rule
- Protected Branch Name Pattern: main
- Enable Status Check: true
- Status check patterns: Check / check\*
- Actions -> Secrets
- PAT: (API token)
## Components ## Components

View File

@ -1,12 +1,12 @@
{ {
"name": "trevstack", "name": "trevstack",
"version": "0.0.30", "version": "0.0.32",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "trevstack", "name": "trevstack",
"version": "0.0.30", "version": "0.0.32",
"devDependencies": { "devDependencies": {
"@bufbuild/protovalidate": "^0.1.1", "@bufbuild/protovalidate": "^0.1.1",
"@connectrpc/connect": "^2.0.2", "@connectrpc/connect": "^2.0.2",

View File

@ -1,7 +1,7 @@
{ {
"name": "trevstack", "name": "trevstack",
"private": true, "private": true,
"version": "0.0.30", "version": "0.0.32",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",

View File

@ -21,7 +21,7 @@
... ...
}: let }: let
pname = "trevstack"; pname = "trevstack";
version = "0.0.30"; version = "0.0.32";
build-systems = [ build-systems = [
"x86_64-linux" "x86_64-linux"
@ -127,7 +127,7 @@
pname = "check-client"; pname = "check-client";
inherit version; inherit version;
src = ./client; src = ./client;
npmDepsHash = "sha256-oSwCfpI1epHLqPy44c+RKmo08LhRQqnVwLuYVMeuu7U="; npmDepsHash = "sha256-iY1tZjYYUETULfyDdq9sjAStzSKe3NZYpZ6F8Y1E00k=";
dontNpmInstall = true; dontNpmInstall = true;
buildPhase = '' buildPhase = ''
@ -190,7 +190,7 @@
client = pkgs.buildNpmPackage { client = pkgs.buildNpmPackage {
inherit pname version; inherit pname version;
src = ./client; src = ./client;
npmDepsHash = "sha256-oSwCfpI1epHLqPy44c+RKmo08LhRQqnVwLuYVMeuu7U="; npmDepsHash = "sha256-iY1tZjYYUETULfyDdq9sjAStzSKe3NZYpZ6F8Y1E00k=";
installPhase = '' installPhase = ''
cp -r build "$out" cp -r build "$out"

View File

@ -3,7 +3,7 @@ servers:
- url: /grpc - url: /grpc
info: info:
title: Trevstack API title: Trevstack API
version: 0.0.30 version: 0.0.32
description: API for Trevstack description: API for Trevstack
contact: contact:
name: Trev name: Trev

View File

@ -68,7 +68,7 @@ func main() {
// Serve gRPC Handlers // Serve gRPC Handlers
api := http.NewServeMux() api := http.NewServeMux()
api.Handle(interceptors.WithCORS(user.NewAuthHandler(vi, sqlc, webAuthn, name, env.Key))) api.Handle(interceptors.WithCORS(user.NewAuthHandler(vi, sqlc, webAuthn, name, env.Key)))
api.Handle(interceptors.WithCORS(user.NewHandler(vi, sqlc, webAuthn, env.Key))) api.Handle(interceptors.WithCORS(user.NewHandler(vi, sqlc, webAuthn, name, env.Key)))
api.Handle(interceptors.WithCORS(item.NewHandler(vi, sqlc, env.Key))) api.Handle(interceptors.WithCORS(item.NewHandler(vi, sqlc, env.Key)))
// Serve web interface // Serve web interface

View File

@ -36,6 +36,7 @@ type Handler struct {
db *sqlc.Queries db *sqlc.Queries
webAuthn *webauthn.WebAuthn webAuthn *webauthn.WebAuthn
key []byte key []byte
name string
sessions *map[int64]*webauthn.SessionData sessions *map[int64]*webauthn.SessionData
mu sync.Mutex mu sync.Mutex
@ -132,7 +133,7 @@ func (h *Handler) GetAPIKey(ctx context.Context, req *connect.Request[userv1.Get
// Generate JWT // Generate JWT
t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{ t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
Issuer: "trevstack", Issuer: h.name,
Subject: strconv.FormatInt(user.ID, 10), Subject: strconv.FormatInt(user.ID, 10),
IssuedAt: &jwt.NumericDate{ IssuedAt: &jwt.NumericDate{
Time: time.Now(), Time: time.Now(),
@ -341,8 +342,8 @@ func transportsToString(transports []protocol.AuthenticatorTransport) string {
return s return s
} }
func NewHandler(vi *validate.Interceptor, db *sqlc.Queries, webauth *webauthn.WebAuthn, key string) (string, http.Handler) { func NewHandler(vi *validate.Interceptor, db *sqlc.Queries, webauth *webauthn.WebAuthn, name string, key string) (string, http.Handler) {
interceptors := connect.WithInterceptors(interceptors.NewAuthInterceptor(key), vi) interceptors := connect.WithInterceptors(vi, interceptors.NewAuthInterceptor(key))
sd := map[int64]*webauthn.SessionData{} sd := map[int64]*webauthn.SessionData{}
return userv1connect.NewUserServiceHandler( return userv1connect.NewUserServiceHandler(
@ -350,6 +351,7 @@ func NewHandler(vi *validate.Interceptor, db *sqlc.Queries, webauth *webauthn.We
db: db, db: db,
webAuthn: webauth, webAuthn: webauth,
key: []byte(key), key: []byte(key),
name: name,
sessions: &sd, sessions: &sd,
mu: sync.Mutex{}, mu: sync.Mutex{},