Skip to content
Open
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,21 @@ flb install-fleetbase
- `--host <host>`: Host or IP address to bind to (default: `localhost`)
- `--environment <environment>`: Environment: `development` or `production` (default: `development`)
- `--directory <directory>`: Installation directory (default: current directory)
- `--app-name <name>`: Application name (default: `Fleetbase`)
- `--non-interactive`: Skip every prompt and use the flags above plus safe defaults (CI/CD, scripted installs)

The installer creates an empty `api/.env` (bind-mounted by `docker-compose.yml`) when one does not exist.

**Example:**
```bash
flb install-fleetbase --host 0.0.0.0 --environment production --directory /opt/fleetbase
```

**Non-interactive example:**
```bash
flb install-fleetbase --non-interactive --directory /opt/fleetbase
```

### Publishing a Extension

To publish a extension, navigate to the extension directory and run:
Expand Down
67 changes: 55 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,36 @@ function buildEnvBlock(vars, indent = 6) {
.join('\n');
}

/**
* Make sure api/.env exists before `docker compose up`.
* docker-compose.yml bind-mounts ./api/.env into the application container; when the
* file is missing Docker creates a *directory* at that path and Laravel cannot boot.
* Values set in docker-compose.override.yml take precedence over this file, so an
* empty file with a comment header is the correct default.
* @param {string} directory resolved installation directory
*/
async function ensureApiEnvFile(directory) {
const envPath = path.join(directory, 'api', '.env');
if (await fs.pathExists(envPath)) {
const stat = await fs.stat(envPath);
if (stat.isDirectory()) {
console.error(`\n✖ ${envPath} is a directory (left behind by an earlier "docker compose up" before the file existed).`);
console.error(' Remove it and re-run the installer.');
process.exit(1);
}
console.log('✔ api/.env already present');
return;
}
await fs.ensureDir(path.dirname(envPath));
await fs.writeFile(envPath, [
'# Fleetbase API environment overrides.',
'# Runtime configuration comes from docker-compose.override.yml and takes precedence',
'# over this file; add per-host secrets or extra overrides here.',
'',
].join('\n'));
console.log('✔ api/.env created');
}

// Command to install Fleetbase via Docker
async function installFleetbaseCommand(options) {
const crypto = require('crypto');
Expand Down Expand Up @@ -1156,8 +1186,15 @@ async function installFleetbaseCommand(options) {
console.log('✔ Pre-flight checks complete\n');

try {
const nonInteractive = !!options.nonInteractive;
if (nonInteractive) {
console.log(' ℹ Non-interactive mode: no prompts; flags and safe defaults are used.');
}

// ── Step 1: Core installation parameters ────────────────────────────
const coreAnswers = await prompt([
// Without a TTY (CI, piped stdin) enquirer would block or throw, so in
// non-interactive mode every core value comes from a flag or its default.
const coreAnswers = nonInteractive ? {} : await prompt([
{
type: 'input',
name: 'host',
Expand Down Expand Up @@ -1186,26 +1223,28 @@ async function installFleetbaseCommand(options) {
type: 'input',
name: 'appName',
message: 'Application name:',
initial: 'Fleetbase',
initial: options.appName || 'Fleetbase',
},
]);

const host = options.host || coreAnswers.host;
const environment = options.environment || coreAnswers.environment;
const directory = options.directory || coreAnswers.directory;
const appName = coreAnswers.appName || 'Fleetbase';
const host = options.host || coreAnswers.host || 'localhost';
const environment = options.environment || coreAnswers.environment || 'development';
const appName = options.appName || coreAnswers.appName || 'Fleetbase';
// Resolve so relative paths (and Git Bash style paths on Windows) work for both
// the file writes below and the `cwd` handed to docker compose.
const directory = path.resolve(options.directory || coreAnswers.directory || process.cwd());

if (!['development', 'production'].includes(environment)) {
console.error(`\n✖ Invalid environment "${environment}". Use "development" or "production".`);
process.exit(1);
}

const useHttps = environment === 'production';
const appDebug = environment !== 'production';
const scSecure = useHttps;
const schemeApi = useHttps ? 'https' : 'http';
const schemeConsole = useHttps ? 'https' : 'http';
const isLocalhost = host === 'localhost' || host === '0.0.0.0' || host === '127.0.0.1';
const nonInteractive = !!options.nonInteractive;

if (nonInteractive) {
console.log(' ℹ Non-interactive mode: all optional steps will use safe defaults.');
}

// ── Step 2: Clone repo if needed ─────────────────────────────────────
const dockerComposePath = path.join(directory, 'docker-compose.yml');
Expand Down Expand Up @@ -1557,6 +1596,9 @@ ${buildEnvBlock(dbEnvVars)}

console.log('✔ Console configuration files updated');

// ── Step 10b: Ensure api/.env exists (bind-mounted by docker-compose.yml) ──
await ensureApiEnvFile(directory);

// ── Step 11: Start containers ─────────────────────────────────────────
console.log('\n⏳ Starting Fleetbase containers...');
console.log(' This may take a few minutes on first run...\n');
Expand Down Expand Up @@ -1998,7 +2040,8 @@ program
.option('--host <host>', 'Host or IP address to bind to (default: localhost)')
.option('--environment <environment>', 'Environment: development or production (default: development)')
.option('--directory <directory>', 'Installation directory (default: current directory)')
.option('--non-interactive', 'Skip all optional prompts and use safe defaults (useful for CI/CD)')
.option('--app-name <name>', 'Application name (default: Fleetbase)')
.option('--non-interactive', 'Skip every prompt; use flags and safe defaults (useful for CI/CD)')
.action(installFleetbaseCommand);

program
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/cli",
"version": "0.0.6",
"version": "0.0.7",
"description": "CLI tool for managing Fleetbase Extensions",
"repository": "https://github.com/fleetbase/fleetbase",
"license": "AGPL-3.0-or-later",
Expand Down
Loading