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
53 changes: 0 additions & 53 deletions deployment/deploy-remotely.sh

This file was deleted.

128 changes: 128 additions & 0 deletions deployment/deploy-remotely.ts
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would add a comment that this file is only for bleu development context

Copy link
Copy Markdown
Contributor Author

@lgahdl lgahdl May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, added a note at the top of the file clarifying this is specific to Bleu's internal deployment workflow.

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env tsx
/**
* deploy-remotely.ts — rsync + SSH deploy or local deploy.
* Replaces deploy-remotely.sh.
*
* NOTE: This script is specific to Bleu's internal deployment workflow.
* It assumes a particular server layout and SSH setup. Adapt as needed for
* your own hosting environment.
*
* Usage:
* npx tsx deployment/deploy-remotely.ts <deploy_target> [env_file_path]
*
* deploy_target:
* - Local deployment (runs manage.ts in this repo)
* host:path Remote deployment via SSH (rsync + scp + ssh)
*
* Note: Remote deployment requires Node 18+ and pnpm installed on the remote host.
* Run `pnpm install` on the remote after the first deploy to install tsx.
*/

import { spawnSync } from "node:child_process";
import { resolve } from "node:path";

function run(
cmd: string,
args: string[],
opts: { cwd?: string; ignoreError?: boolean } = {}
): void {
console.log(`+ ${cmd} ${args.join(" ")}`);
const result = spawnSync(cmd, args, {
stdio: "inherit",
cwd: opts.cwd,
});
if (!opts.ignoreError && result.status !== 0) {
process.exit(result.status ?? 1);
}
}

function runCapture(cmd: string, args: string[]): string {
const result = spawnSync(cmd, args, { encoding: "utf-8" });
if (result.status !== 0) {
console.error(`Command failed: ${cmd} ${args.join(" ")}`);
console.error(result.stderr);
process.exit(result.status ?? 1);
}
return result.stdout.trim();
}

function usage(): never {
console.error(
`Usage: tsx deployment/deploy-remotely.ts <deploy_target> [env_file_path]

deploy_target:
- Local deployment
host:path Remote deployment via SSH

env_file_path: path to .env file (default: .env)
`
);
process.exit(1);
}

const [deployTarget, envFilePath = ".env"] = process.argv.slice(2);

if (!deployTarget) {
usage();
}

const appRevision = runCapture("git", ["rev-parse", "--short", "HEAD"]);
const repoRootDir = runCapture("git", ["rev-parse", "--show-toplevel"]);
const manageCmd = process.env["MANAGE_CMD_OVERRIDE"] ?? "up";

if (deployTarget === "-") {
// Local deployment
const absoluteEnvFile = resolve(envFilePath);
run(
"npx",
[
"tsx",
"deployment/manage.ts",
manageCmd,
"--env-file",
absoluteEnvFile,
"--revision",
appRevision,
],
{ cwd: repoRootDir }
);
} else if (/^[^:]+:.+/.test(deployTarget)) {
// Remote deployment via SSH
const colonIdx = deployTarget.indexOf(":");
const sshHost = deployTarget.slice(0, colonIdx);
const remotePath = deployTarget.slice(colonIdx + 1);

// rsync repo to remote host
run("rsync", [
"-avz",
"--delete",
"--mkpath",
"--exclude=.git",
"--exclude=node_modules",
"--exclude=.env",
"--exclude=.env.local",
"--exclude=.vite",
"--exclude=*.log",
"--exclude=tmp/",
`${repoRootDir}/`,
`${sshHost}:${remotePath}/`,
]);

// Copy env file to remote deployment directory
const remoteEnvPath = `${remotePath}/deployment/.env`;
run("scp", [envFilePath, `${sshHost}:${remoteEnvPath}`]);

// Run manage.ts on the remote host
// Note: The remote host must have Node 18+ and pnpm installed.
// After the first deploy, run `pnpm install` on the remote to install tsx.
const remoteDeployDir = `${remotePath}/deployment`;
run("ssh", [
sshHost,
`cd ${remoteDeployDir} && npx tsx manage.ts ${manageCmd} --env-file .env --revision ${appRevision}`,
]);
} else {
console.error(
"Error: <deploy_target> must be '-' (local) or SSH_HOST:PATH (remote)"
);
usage();
}
20 changes: 17 additions & 3 deletions deployment/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@ services:
postgres:
image: postgres:16
restart: unless-stopped
command: ["bash", "/start-db.sh"]
# Memory tuning values are computed for the default POSTGRES_MEMORY_LIMIT=1G (1024 MB):
# shared_buffers = 20% of 1024 MB = 204 MB
# maintenance_work_mem = 5% of 1024 MB = 51 MB
# effective_cache_size = 50% of 1024 MB = 512 MB
# work_mem = 25% of 1024 MB / 100 connections = 2 MB
# To adjust for a different memory limit, change the -c flags proportionally.
command: >-
postgres
-c max_connections=100
-c shared_buffers=204MB
-c work_mem=2MB
-c maintenance_work_mem=51MB
-c effective_cache_size=512MB
-c max_wal_size=1GB
-c min_wal_size=256MB
-c checkpoint_completion_target=0.9
-c wal_buffers=8MB
environment:
POSTGRES_DB: ${POSTGRES_DB:?error}
POSTGRES_USER: ${POSTGRES_USER:?error}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?error}
POSTGRES_MEMORY_LIMIT: ${POSTGRES_MEMORY_LIMIT:-1G}
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=en_US.UTF-8"
shm_size: 256m
ports:
- "${POSTGRES_PORT:-5433}:5432"
volumes:
- ./static/start-db.sh:/start-db.sh:ro
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
Expand Down
93 changes: 0 additions & 93 deletions deployment/manage.sh

This file was deleted.

Loading
Loading