Merge branch 'main' into tests/integration
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m51s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped

This commit is contained in:
2026-01-22 19:18:27 +01:00
7 changed files with 401 additions and 144 deletions

186
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,186 @@
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
# Job 1: Lint and Typecheck (Fast feedback)
lint-typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run Typecheck
run: npm run typecheck
# Job 2: Unit and Integration Tests
tests:
runs-on: ubuntu-latest
needs: lint-typecheck
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run Unit Tests
run: npm run test:unit
- name: Run Integration Tests
run: npm run test:integration
# Job 3: Contract Tests (API/Website compatibility)
contract-tests:
runs-on: ubuntu-latest
needs: lint-typecheck
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run API Contract Validation
run: npm run test:api:contracts
- name: Generate OpenAPI spec
run: npm run api:generate-spec
- name: Generate TypeScript types
run: npm run api:generate-types
- name: Run Contract Compatibility Check
run: npm run test:contract:compatibility
- name: Verify Website Type Checking
run: npm run website:type-check
- name: Upload generated types as artifacts
uses: actions/upload-artifact@v3
with:
name: generated-types
path: apps/website/lib/types/generated/
retention-days: 7
# Job 4: E2E Tests (Only on main/develop push, not on PRs)
e2e-tests:
runs-on: ubuntu-latest
needs: [lint-typecheck, tests, contract-tests]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run E2E Tests
run: npm run test:e2e
# Job 5: Comment PR with results (Only on PRs)
comment-pr:
runs-on: ubuntu-latest
needs: [lint-typecheck, tests, contract-tests]
if: github.event_name == 'pull_request'
steps:
- name: Comment PR with results
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const path = require('path');
// Read any contract change reports
const reportPath = path.join(process.cwd(), 'contract-report.json');
if (fs.existsSync(reportPath)) {
const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
const comment = `
## 🔍 CI Results
✅ **All checks passed!**
### Changes Summary:
- Total changes: ${report.totalChanges}
- Breaking changes: ${report.breakingChanges}
- Added: ${report.added}
- Removed: ${report.removed}
- Modified: ${report.modified}
Generated types are available as artifacts.
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
}
# Job 6: Commit generated types (Only on main branch push)
commit-types:
runs-on: ubuntu-latest
needs: [lint-typecheck, tests, contract-tests]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Generate and snapshot types
run: |
npm run api:generate-spec
npm run api:generate-types
- name: Commit generated types
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add apps/website/lib/types/generated/
git diff --staged --quiet || git commit -m "chore: update generated API types [skip ci]"
git push

View File

@@ -1,110 +0,0 @@
name: Contract Testing
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
contract-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run API contract validation
run: npm run test:api:contracts
- name: Generate OpenAPI spec
run: npm run api:generate-spec
- name: Generate TypeScript types
run: npm run api:generate-types
- name: Run contract compatibility check
run: npm run test:contract:compatibility
- name: Verify website type checking
run: npm run website:type-check
- name: Upload generated types as artifacts
uses: actions/upload-artifact@v3
with:
name: generated-types
path: apps/website/lib/types/generated/
retention-days: 7
- name: Comment PR with results
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const path = require('path');
// Read any contract change reports
const reportPath = path.join(process.cwd(), 'contract-report.json');
if (fs.existsSync(reportPath)) {
const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
const comment = `
## 🔍 Contract Testing Results
✅ **All contract tests passed!**
### Changes Summary:
- Total changes: ${report.totalChanges}
- Breaking changes: ${report.breakingChanges}
- Added: ${report.added}
- Removed: ${report.removed}
- Modified: ${report.modified}
Generated types are available as artifacts.
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
}
contract-snapshot:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate and snapshot types
run: |
npm run api:generate-spec
npm run api:generate-types
- name: Commit generated types
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add apps/website/lib/types/generated/
git diff --staged --quiet || git commit -m "chore: update generated API types [skip ci]"
git push

View File

@@ -1 +1 @@
npm test
npx lint-staged

View File

@@ -14,6 +14,17 @@ GridPilot streamlines the organization and administration of iRacing racing leag
- **Docker** and **Docker Compose**
- Git for version control
### Windows Compatibility
This project is fully compatible with Windows 11, macOS, and Linux. All development scripts have been updated to work across all platforms:
- ✅ Cross-platform npm scripts
- ✅ Windows-compatible Docker commands
- ✅ Universal test commands
- ✅ Cross-platform cleanup scripts
For detailed information, see [Windows Compatibility Guide](docs/WINDOWS_COMPATIBILITY.md).
## Installation
```bash
@@ -45,7 +56,7 @@ npm test
Individual applications support hot reload and watch mode during development:
- **web-api**: Backend REST API server
- **web-client**: Frontend React application
- **web-client**: Frontend React application
- **companion**: Desktop companion application
## Testing Commands
@@ -53,12 +64,28 @@ Individual applications support hot reload and watch mode during development:
GridPilot follows strict BDD (Behavior-Driven Development) with comprehensive test coverage.
### Local Verification Pipeline
Run this sequence before pushing to ensure correctness:
```bash
npm run lint && npm run typecheck && npm run test:unit && npm run test:integration
```
GridPilot uses **lint-staged** to automatically validate only changed files on commit:
- `eslint --fix` runs on changed JS/TS/TSX files
- `vitest related --run` runs tests related to changed files
- `prettier --write` formats JSON, MD, and YAML files
This ensures fast commits without running the full test suite.
### Pre-Push Hook
A **pre-push hook** runs the full verification pipeline before pushing to remote:
- `npm run lint` - Check for linting errors
- `npm run typecheck` - Verify TypeScript types
- `npm run test:unit` - Run unit tests
- `npm run test:integration` - Run integration tests
You can skip this with `git push --no-verify` if needed.
### Individual Commands
```bash
# Run all tests
npm test
@@ -136,4 +163,4 @@ Comprehensive documentation is available in the [`/docs`](docs/) directory:
## License
MIT License - see [LICENSE](LICENSE) file for details.
MIT License - see [LICENSE](LICENSE) file for details.

View File

@@ -45,6 +45,7 @@
"glob": "^13.0.0",
"husky": "^9.1.7",
"jsdom": "^22.1.0",
"lint-staged": "^15.2.10",
"openapi-typescript": "^7.4.3",
"prettier": "^3.0.0",
"puppeteer": "^24.31.0",
@@ -71,7 +72,7 @@
"api:sync-types": "npm run api:generate-spec && npm run api:generate-types",
"api:test": "vitest run --config vitest.api.config.ts",
"build": "echo 'Build all packages placeholder - to be configured'",
"chrome:debug": "open -a 'Google Chrome' --args --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug",
"chrome:debug": "node -e \"console.log('Chrome debug: Open Chrome manually with --remote-debugging-port=9222')\"",
"companion:build": "npm run build --workspace=@gridpilot/companion",
"companion:dev": "npm run dev --workspace=@gridpilot/companion",
"companion:start": "npm run start --workspace=@gridpilot/companion",
@@ -79,25 +80,17 @@
"deploy:website:preview": "npx vercel deploy --cwd apps/website",
"deploy:website:prod": "npx vercel deploy --prod",
"dev": "echo 'Development server placeholder - to be configured'",
"docker:dev": "sh -lc \"set -e; echo '[docker] Starting dev environment...'; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then echo '[docker] Dev environment already running, attaching...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml logs -f; else echo '[docker] Starting fresh dev environment...'; COMPOSE_PARALLEL_LIMIT=1 docker-compose -p gridpilot-dev -f docker-compose.dev.yml up; fi\"",
"docker:dev:build": "sh -lc \"set -e; echo '[docker] Building and starting dev environment...'; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then echo '[docker] Stopping existing environment first...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml down --remove-orphans; fi; COMPOSE_PARALLEL_LIMIT=1 docker-compose -p gridpilot-dev -f docker-compose.dev.yml up --build\"",
"docker:dev:clean": "sh -lc \"set -e; echo '[docker] Cleaning up dev environment...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml down -v --remove-orphans --volumes; echo '[docker] Cleanup complete'\"",
"docker:dev:down": "sh -lc \"set -e; echo '[docker] Stopping dev environment...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml down --remove-orphans; echo '[docker] Stopped'\"",
"docker:dev:force": "sh -lc \"set -e; echo '[docker] Force starting dev environment...'; echo '[docker] Stopping any existing environment...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml down --remove-orphans 2>/dev/null || true; echo '[docker] Starting fresh...'; COMPOSE_PARALLEL_LIMIT=1 docker-compose -p gridpilot-dev -f docker-compose.dev.yml up\"",
"docker:dev:inmemory": "sh -lc \"GRIDPILOT_API_PERSISTENCE=inmemory npm run docker:dev:up\"",
"docker:dev:logs": "sh -lc \"set -e; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then docker-compose -p gridpilot-dev -f docker-compose.dev.yml logs -f; else echo '[docker] No running containers to show logs for'; echo '[docker] Start with: npm run docker:dev'; fi\"",
"docker:dev:postgres": "sh -lc \"GRIDPILOT_API_PERSISTENCE=postgres npm run docker:dev:up\"",
"docker:dev:ps": "sh -lc \"set -e; echo '[docker] Container status:'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps; echo ''; echo '[docker] Running containers:'; docker ps --filter name=gridpilot-dev --format 'table {{.Names}}\\t{{.Status}}\\t{{.Ports}}'\"",
"docker:dev:reseed": "sh -lc \"set -e; echo '[docker] Reseeding with fresh database...'; echo '[docker] Stopping and removing volumes...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml down -v --remove-orphans; echo '[docker] Removing any legacy volumes...'; docker volume rm -f gridpilot_dev_db_data 2>/dev/null || true; echo '[docker] Starting fresh environment with force reseed...'; GRIDPILOT_API_FORCE_RESEED=true COMPOSE_PARALLEL_LIMIT=1 docker-compose -p gridpilot-dev -f docker-compose.dev.yml up\"",
"docker:dev:restart": "sh -lc \"set -e; echo '[docker] Restarting services...'; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then docker-compose -p gridpilot-dev -f docker-compose.dev.yml restart; echo '[docker] Restarted'; else echo '[docker] No running containers to restart'; echo '[docker] Start with: npm run docker:dev'; fi\"",
"docker:dev:status": "sh -lc \"set -e; echo '[docker] Checking dev environment status...'; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then echo '[docker] ✓ Environment is RUNNING'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps; echo ''; echo '[docker] Services health:'; docker ps --filter name=gridpilot-dev --format 'table {{.Names}}\\t{{.Status}}\\t{{.RunningFor}}'; else echo '[docker] ✗ Environment is STOPPED'; echo '[docker] Start with: npm run docker:dev'; fi\"",
"docker:dev:up": "sh -lc \"set -e; echo '[docker] Starting dev environment...'; if docker-compose -p gridpilot-dev -f docker-compose.dev.yml ps -q 2>/dev/null | grep -q .; then echo '[docker] Already running, attaching to logs...'; docker-compose -p gridpilot-dev -f docker-compose.dev.yml logs -f; else COMPOSE_PARALLEL_LIMIT=1 docker-compose -p gridpilot-dev -f docker-compose.dev.yml up; fi\"",
"docker:e2e:build": "sh -lc \"echo '[e2e] Building website image...'; docker build -f apps/website/Dockerfile.e2e -t gridpilot-website-e2e . && echo '[e2e] Starting full stack...'; docker-compose -f docker-compose.e2e.yml up -d --build\"",
"docker:e2e:clean": "sh -lc \"echo '[e2e] Cleaning up...'; docker-compose -f docker-compose.e2e.yml down -v --remove-orphans; docker rmi gridpilot-website-e2e 2>/dev/null || true; echo '[e2e] Cleanup complete'\"",
"docker:e2e:down": "sh -lc \"echo '[e2e] Stopping e2e environment...'; docker-compose -f docker-compose.e2e.yml down --remove-orphans; echo '[e2e] Stopped'\"",
"docker:e2e:logs": "sh -lc \"docker-compose -f docker-compose.e2e.yml logs -f\"",
"docker:e2e:ps": "sh -lc \"docker-compose -f docker-compose.e2e.yml ps\"",
"docker:e2e:up": "sh -lc \"echo '[e2e] Starting full stack...'; docker-compose -f docker-compose.e2e.yml up -d --build\"",
"docker:dev": "node scripts/docker.js dev",
"docker:dev:build": "node scripts/docker.js dev:build",
"docker:dev:clean": "node scripts/docker.js dev:clean",
"docker:dev:down": "node scripts/docker.js dev:down",
"docker:dev:inmemory": "cross-env GRIDPILOT_API_PERSISTENCE=inmemory npm run docker:dev:up",
"docker:dev:postgres": "cross-env GRIDPILOT_API_PERSISTENCE=postgres npm run docker:dev:up",
"docker:dev:up": "node scripts/docker.js dev:up",
"docker:e2e:build": "node scripts/docker.js e2e:build",
"docker:e2e:clean": "node scripts/docker.js e2e:clean",
"docker:e2e:down": "node scripts/docker.js e2e:down",
"docker:e2e:up": "node scripts/docker.js e2e:up",
"docker:prod": "docker-compose -p gridpilot-prod -f docker-compose.prod.yml up -d",
"docker:prod:build": "docker-compose -p gridpilot-prod -f docker-compose.prod.yml up -d --build",
"docker:prod:clean": "docker-compose -p gridpilot-prod -f docker-compose.prod.yml down -v",
@@ -115,17 +108,17 @@
"prepare": "husky install || true",
"smoke:website": "npm run website:build && npx playwright test -c playwright.website.config.ts",
"smoke:website:docker": "npx playwright test -c playwright.website.config.ts",
"test": "vitest run \"$@\"",
"test": "vitest run",
"test:api:contracts": "vitest run --config vitest.api.config.ts apps/api/src/shared/testing/contractValidation.test.ts",
"test:api:smoke": "sh -lc \"echo '🚀 Running API smoke tests...'; npx playwright test tests/e2e/api/api-smoke.test.ts --reporter=json,html\"",
"test:api:smoke:docker": "sh -lc \"echo '🚀 Running API smoke tests in Docker...'; docker-compose -f docker-compose.e2e.yml run --rm playwright npx playwright test tests/e2e/api/api-smoke.test.ts --reporter=json,html\"",
"test:api:smoke": "npx playwright test tests/e2e/api/api-smoke.test.ts --reporter=json,html",
"test:api:smoke:docker": "docker-compose -f docker-compose.e2e.yml run --rm playwright npx playwright test tests/e2e/api/api-smoke.test.ts --reporter=json,html",
"test:companion-hosted": "vitest run --config vitest.e2e.config.ts tests/e2e/companion/companion-ui-full-workflow.e2e.test.ts",
"test:contract:compatibility": "tsx scripts/contract-compatibility.ts",
"test:contracts": "tsx scripts/run-contract-tests.ts",
"test:e2e": "vitest run --config vitest.e2e.config.ts",
"test:e2e:docker": "vitest run --config vitest.e2e.config.ts tests/e2e/docker/",
"test:e2e:run": "sh -lc \"npm run docker:e2e:up && echo '[e2e] Running Playwright tests...'; docker-compose -f docker-compose.e2e.yml run --rm playwright npx playwright test\"",
"test:e2e:website": "sh -lc \"set -e; trap 'npm run docker:e2e:down' EXIT; npm run docker:e2e:up && echo '[e2e] Waiting for services...'; sleep 10 && echo '[e2e] Running Playwright tests...'; docker-compose -f docker-compose.e2e.yml run --rm playwright\"",
"test:e2e:run": "node scripts/docker.js e2e:up && docker-compose -f docker-compose.e2e.yml run --rm playwright npx playwright test",
"test:e2e:website": "node scripts/docker.js e2e:up && sleep 10 && docker-compose -f docker-compose.e2e.yml run --rm playwright",
"test:hosted-real": "vitest run --config vitest.e2e.config.ts tests/e2e/hosted-real/",
"test:integration": "vitest run tests/integration",
"test:smoke": "vitest run --config vitest.smoke.config.ts",
@@ -136,8 +129,9 @@
"test:unit": "vitest run tests/unit",
"test:watch": "vitest watch",
"test:website:types": "vitest run --config vitest.website.config.ts apps/website/lib/types/contractConsumption.test.ts",
"verify": "npm run lint && npm run typecheck && npm run test:unit && npm run test:integration",
"typecheck": "npm run typecheck:targets",
"typecheck:grep": "npm run typescript | grep",
"typecheck:grep": "npm run typescript",
"typecheck:root": "npx tsc --noEmit --project tsconfig.json",
"typecheck:targets": "npx tsc --noEmit -p apps/website/tsconfig.json && npx tsc --noEmit -p apps/api/tsconfig.json && npx tsc --noEmit -p adapters/tsconfig.json && npx tsc --noEmit -p core/tsconfig.json",
"website:build": "npm run env:website:merge && npm run build --workspace=@gridpilot/website",
@@ -147,10 +141,19 @@
"website:start": "npm run start --workspace=@gridpilot/website",
"website:type-check": "npm run type-check --workspace=@gridpilot/website"
},
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"vitest related --run"
],
"*.{json,md,yml}": [
"prettier --write"
]
},
"version": "0.1.0",
"workspaces": [
"core/*",
"apps/*",
"testing/*"
]
}
}

100
plans/ci-optimization.md Normal file
View File

@@ -0,0 +1,100 @@
# CI/CD & Dev Experience Optimization Plan
## Current Situation
- **Husky `pre-commit`**: Runs `npm test` (Vitest) on every commit. This likely runs the entire test suite, which is slow and frustrating for developers.
- **Gitea Actions**: Currently only has `contract-testing.yml`.
- **Missing**: No automated linting or type-checking in CI, no tiered testing strategy.
## Proposed Strategy: The "Fast Feedback Loop"
We will implement a tiered approach to balance speed and safety.
### 1. Local Development (Husky + lint-staged)
**Goal**: Prevent obvious errors from entering the repo without slowing down the dev.
- **Trigger**: `pre-commit`
- **Action**: Only run on **staged files**.
- **Tasks**:
- `eslint --fix`
- `prettier --write`
- `vitest related` (only run tests related to changed files)
### 2. Pull Request (Gitea Actions)
**Goal**: Ensure the branch is stable and doesn't break the build or other modules.
- **Trigger**: PR creation and updates.
- **Tasks**:
- Full `lint`
- Full `typecheck` (crucial for monorepo integrity)
- Full `unit tests`
- `integration tests`
- `contract tests`
### 3. Merge to Main / Release (Gitea Actions)
**Goal**: Final verification before deployment.
- **Trigger**: Push to `main` or `develop`.
- **Tasks**:
- Everything from PR stage.
- `e2e tests` (Playwright) - these are the slowest and most expensive.
---
## Implementation Steps
### Step 1: Install and Configure `lint-staged`
We need to add `lint-staged` to [`package.json`](package.json) and update the Husky hook.
### Step 2: Optimize Husky Hook
Update [`.husky/pre-commit`](.husky/pre-commit) to run `npx lint-staged` instead of `npm test`.
### Step 3: Create Comprehensive CI Workflow
Create `.github/workflows/ci.yml` (Gitea Actions compatible) to handle the heavy lifting.
---
## Workflow Diagram
```mermaid
graph TD
A[Developer Commits] --> B{Husky pre-commit}
B -->|lint-staged| C[Lint/Format Changed Files]
C --> D[Run Related Tests]
D --> E[Commit Success]
E --> F[Push to PR]
F --> G{Gitea CI PR Job}
G --> H[Full Lint & Typecheck]
G --> I[Full Unit & Integration Tests]
G --> J[Contract Tests]
J --> K{Merge to Main}
K --> L{Gitea CI Main Job}
L --> M[All PR Checks]
L --> N[Full E2E Tests]
N --> O[Deploy/Release]
```
## Proposed `lint-staged` Configuration
```json
{
"*.{js,ts,tsx}": ["eslint --fix", "vitest related --run"],
"*.{json,md,yml}": ["prettier --write"]
}
```
---
## Questions for the User
1. Do you want to include `typecheck` in the `pre-commit` hook? (Note: `tsc` doesn't support linting only changed files easily, so it usually checks the whole project, which might be slow).
2. Should we run `integration tests` on every PR, or only on merge to `main`?
3. Are there specific directories that should be excluded from this automated flow?

51
scripts/docker.js Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env node
const { execSync } = require('child_process');
const os = require('os');
function isWindows() {
return os.platform() === 'win32';
}
function runCommand(command) {
try {
execSync(command, {
stdio: 'inherit',
shell: isWindows() ? 'cmd.exe' : 'sh'
});
} catch (error) {
process.exit(1);
}
}
function main() {
const args = process.argv.slice(2);
const command = args[0];
if (!command) {
console.error('Usage: node scripts/docker.js <command>');
console.error('Available commands: dev, dev:build, dev:clean, dev:down, dev:up, e2e:build, e2e:clean, e2e:down, e2e:up');
process.exit(1);
}
const commands = {
'dev': 'docker-compose -p gridpilot-dev -f docker-compose.dev.yml up',
'dev:build': 'docker-compose -p gridpilot-dev -f docker-compose.dev.yml up --build',
'dev:clean': 'docker-compose -p gridpilot-dev -f docker-compose.dev.yml down -v --remove-orphans --volumes',
'dev:down': 'docker-compose -p gridpilot-dev -f docker-compose.dev.yml down --remove-orphans',
'dev:up': 'docker-compose -p gridpilot-dev -f docker-compose.dev.yml up',
'e2e:build': 'docker build -f apps/website/Dockerfile.e2e -t gridpilot-website-e2e . && docker-compose -f docker-compose.e2e.yml up -d --build',
'e2e:clean': 'docker-compose -f docker-compose.e2e.yml down -v --remove-orphans && docker rmi gridpilot-website-e2e 2>/dev/null || true',
'e2e:down': 'docker-compose -f docker-compose.e2e.yml down --remove-orphans',
'e2e:up': 'docker-compose -f docker-compose.e2e.yml up -d --build'
};
if (!commands[command]) {
console.error(`Unknown command: ${command}`);
process.exit(1);
}
runCommand(commands[command]);
}
main();