Compare commits
2 Commits
e8a638d11d
...
d89a58c0ab
| Author | SHA1 | Date | |
|---|---|---|---|
| d89a58c0ab | |||
| 8f37274cee |
|
|
@ -11,7 +11,30 @@ source "$ROOT_DIR/scripts/config.sh"
|
||||||
git push origin main
|
git push origin main
|
||||||
|
|
||||||
# SSH to target and update
|
# SSH to target and update
|
||||||
ssh "$HOST" "cd $DEST && git pull origin main && bun run build && sudo systemctl restart toes.service"
|
ssh "$HOST" "cd $DEST && git pull origin main && bun run build"
|
||||||
|
|
||||||
|
# Sync default apps/tools from repo to APPS_DIR
|
||||||
|
echo "=> Syncing default apps..."
|
||||||
|
ssh "$HOST" bash -s "$DEST" "$APPS_DIR" <<'SCRIPT'
|
||||||
|
DEST="$1"
|
||||||
|
APPS_DIR="$2"
|
||||||
|
for app_dir in "$DEST"/apps/*/; do
|
||||||
|
app=$(basename "$app_dir")
|
||||||
|
for version_dir in "$app_dir"*/; do
|
||||||
|
[ -d "$version_dir" ] || continue
|
||||||
|
version=$(basename "$version_dir")
|
||||||
|
[ -f "$version_dir/package.json" ] || continue
|
||||||
|
target="$APPS_DIR/$app/$version"
|
||||||
|
mkdir -p "$target"
|
||||||
|
cp -a "$version_dir"/. "$target"/
|
||||||
|
rm -f "$APPS_DIR/$app/current"
|
||||||
|
echo " $app/$version"
|
||||||
|
(cd "$target" && bun install --frozen-lockfile 2>/dev/null || bun install)
|
||||||
|
done
|
||||||
|
done
|
||||||
|
SCRIPT
|
||||||
|
|
||||||
|
ssh "$HOST" "sudo systemctl restart toes.service"
|
||||||
|
|
||||||
echo "=> Deployed to $HOST"
|
echo "=> Deployed to $HOST"
|
||||||
echo "=> Visit $URL"
|
echo "=> Visit $URL"
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,62 @@ interface EnvVar {
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function envList(name: string | undefined) {
|
function parseKeyValue(keyOrKeyValue: string, valueArg?: string): { key: string, value: string } | null {
|
||||||
|
if (valueArg !== undefined) {
|
||||||
|
const key = keyOrKeyValue.trim()
|
||||||
|
if (!key) { console.error('Key cannot be empty'); return null }
|
||||||
|
return { key, value: valueArg }
|
||||||
|
}
|
||||||
|
const eqIndex = keyOrKeyValue.indexOf('=')
|
||||||
|
if (eqIndex === -1) {
|
||||||
|
console.error('Invalid format. Use: KEY value or KEY=value')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const key = keyOrKeyValue.slice(0, eqIndex).trim()
|
||||||
|
if (!key) { console.error('Key cannot be empty'); return null }
|
||||||
|
return { key, value: keyOrKeyValue.slice(eqIndex + 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function globalEnvSet(keyOrKeyValue: string, valueArg?: string) {
|
||||||
|
const parsed = parseKeyValue(keyOrKeyValue, valueArg)
|
||||||
|
if (!parsed) return
|
||||||
|
const { key, value } = parsed
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await post<{ ok: boolean, error?: string }>('/api/env', { key, value })
|
||||||
|
if (result?.ok) {
|
||||||
|
console.log(color.green(`Set global ${color.bold(key.toUpperCase())}`))
|
||||||
|
} else {
|
||||||
|
console.error(result?.error ?? 'Failed to set variable')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function envList(name: string | undefined, opts: { global?: boolean }) {
|
||||||
|
if (opts.global) {
|
||||||
|
const vars = await get<EnvVar[]>('/api/env')
|
||||||
|
console.log(color.bold().cyan('Global Environment Variables'))
|
||||||
|
console.log()
|
||||||
|
if (!vars || vars.length === 0) {
|
||||||
|
console.log(color.gray(' No global environment variables set'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const v of vars) {
|
||||||
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const appName = resolveAppName(name)
|
const appName = resolveAppName(name)
|
||||||
if (!appName) return
|
if (!appName) return
|
||||||
|
|
||||||
const vars = await get<EnvVar[]>(`/api/apps/${appName}/env`)
|
const [vars, globalVars] = await Promise.all([
|
||||||
|
get<EnvVar[]>(`/api/apps/${appName}/env`),
|
||||||
|
get<EnvVar[]>('/api/env'),
|
||||||
|
])
|
||||||
|
|
||||||
if (!vars) {
|
if (!vars) {
|
||||||
console.error(`App not found: ${appName}`)
|
console.error(`App not found: ${appName}`)
|
||||||
return
|
return
|
||||||
|
|
@ -20,7 +71,9 @@ export async function envList(name: string | undefined) {
|
||||||
console.log(color.bold().cyan(`Environment Variables for ${appName}`))
|
console.log(color.bold().cyan(`Environment Variables for ${appName}`))
|
||||||
console.log()
|
console.log()
|
||||||
|
|
||||||
if (vars.length === 0) {
|
const appKeys = new Set(vars.map(v => v.key))
|
||||||
|
|
||||||
|
if (vars.length === 0 && (!globalVars || globalVars.length === 0)) {
|
||||||
console.log(color.gray(' No environment variables set'))
|
console.log(color.gray(' No environment variables set'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -28,31 +81,30 @@ export async function envList(name: string | undefined) {
|
||||||
for (const v of vars) {
|
for (const v of vars) {
|
||||||
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (globalVars && globalVars.length > 0) {
|
||||||
|
const inherited = globalVars.filter(v => !appKeys.has(v.key))
|
||||||
|
if (inherited.length > 0) {
|
||||||
|
if (vars.length > 0) console.log()
|
||||||
|
console.log(color.gray(' Inherited from global:'))
|
||||||
|
for (const v of inherited) {
|
||||||
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function envSet(name: string | undefined, keyOrKeyValue: string, valueArg?: string) {
|
export async function envSet(name: string | undefined, keyOrKeyValue: string, valueArg: string | undefined, opts: { global?: boolean }) {
|
||||||
let key: string
|
// With --global, args shift: name becomes key, key becomes value
|
||||||
let value: string
|
if (opts.global) {
|
||||||
|
const actualKey = name ?? keyOrKeyValue
|
||||||
if (valueArg !== undefined) {
|
const actualValue = name ? keyOrKeyValue : valueArg
|
||||||
// KEY value format
|
return globalEnvSet(actualKey, actualValue)
|
||||||
key = keyOrKeyValue.trim()
|
|
||||||
value = valueArg
|
|
||||||
} else {
|
|
||||||
// KEY=value format
|
|
||||||
const eqIndex = keyOrKeyValue.indexOf('=')
|
|
||||||
if (eqIndex === -1) {
|
|
||||||
console.error('Invalid format. Use: KEY value or KEY=value')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
key = keyOrKeyValue.slice(0, eqIndex).trim()
|
|
||||||
value = keyOrKeyValue.slice(eqIndex + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key) {
|
const parsed = parseKeyValue(keyOrKeyValue, valueArg)
|
||||||
console.error('Key cannot be empty')
|
if (!parsed) return
|
||||||
return
|
const { key, value } = parsed
|
||||||
}
|
|
||||||
|
|
||||||
const appName = resolveAppName(name)
|
const appName = resolveAppName(name)
|
||||||
if (!appName) return
|
if (!appName) return
|
||||||
|
|
@ -70,7 +122,21 @@ export async function envSet(name: string | undefined, keyOrKeyValue: string, va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function envRm(name: string | undefined, key: string) {
|
export async function envRm(name: string | undefined, key: string, opts: { global?: boolean }) {
|
||||||
|
// With --global, args shift: name becomes key
|
||||||
|
if (opts.global) {
|
||||||
|
const actualKey = name ?? key
|
||||||
|
if (!actualKey) {
|
||||||
|
console.error('Key is required')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const ok = await del(`/api/env/${actualKey.toUpperCase()}`)
|
||||||
|
if (ok) {
|
||||||
|
console.log(color.green(`Removed global ${color.bold(actualKey.toUpperCase())}`))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!key) {
|
if (!key) {
|
||||||
console.error('Key is required')
|
console.error('Key is required')
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ const env = program
|
||||||
.helpGroup('Config:')
|
.helpGroup('Config:')
|
||||||
.description('Manage environment variables')
|
.description('Manage environment variables')
|
||||||
.argument('[name]', 'app name (uses current directory if omitted)')
|
.argument('[name]', 'app name (uses current directory if omitted)')
|
||||||
|
.option('-g, --global', 'manage global variables shared by all apps')
|
||||||
.action(envList)
|
.action(envList)
|
||||||
|
|
||||||
env
|
env
|
||||||
|
|
@ -239,6 +240,7 @@ env
|
||||||
.argument('[name]', 'app name (uses current directory if omitted)')
|
.argument('[name]', 'app name (uses current directory if omitted)')
|
||||||
.argument('<key>', 'variable name')
|
.argument('<key>', 'variable name')
|
||||||
.argument('[value]', 'variable value (or use KEY=value format)')
|
.argument('[value]', 'variable value (or use KEY=value format)')
|
||||||
|
.option('-g, --global', 'set a global variable shared by all apps')
|
||||||
.action(envSet)
|
.action(envSet)
|
||||||
|
|
||||||
env
|
env
|
||||||
|
|
@ -246,6 +248,7 @@ env
|
||||||
.description('Remove an environment variable')
|
.description('Remove an environment variable')
|
||||||
.argument('[name]', 'app name (uses current directory if omitted)')
|
.argument('[name]', 'app name (uses current directory if omitted)')
|
||||||
.argument('<key>', 'variable name to remove')
|
.argument('<key>', 'variable name to remove')
|
||||||
|
.option('-g, --global', 'remove a global variable')
|
||||||
.action(envRm)
|
.action(envRm)
|
||||||
|
|
||||||
program
|
program
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user