create-odoo-module 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,390 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { writeFile, mkdirp } = require('../utils/file-system');
5
+ const logger = require('../utils/logger');
6
+
7
+ /**
8
+ * Generate deploy scripts: Linux bash, Windows PowerShell, Docker Compose.
9
+ */
10
+ async function generateDeployScripts(targetDir, config) {
11
+ const s = config.moduleNameSnake;
12
+ const L = config.moduleNameLabel;
13
+ const M = config.moduleNameOdoo;
14
+
15
+ logger.verbose('Generating deploy scripts...');
16
+
17
+ const scriptsDir = path.join(targetDir, 'scripts');
18
+ await mkdirp(scriptsDir);
19
+
20
+ const files = [
21
+ [path.join(scriptsDir, 'deploy.sh'), genDeployBash(s, L, M, config)],
22
+ [path.join(scriptsDir, 'deploy.ps1'), genDeployPowershell(s, L, M, config)],
23
+ [path.join(scriptsDir, 'docker-compose.yml'), genDockerCompose(s, config)],
24
+ ];
25
+
26
+ if (config.withCi) {
27
+ await mkdirp(path.join(targetDir, '.github', 'workflows'));
28
+ files.push([
29
+ path.join(targetDir, '.github', 'workflows', 'ci.yml'),
30
+ genGithubActions(s, L, M, config),
31
+ ]);
32
+ }
33
+
34
+ await Promise.all(files.map(([f, c]) => writeFile(f, c)));
35
+
36
+ // Make bash scripts executable (best effort)
37
+ try {
38
+ const { execa } = require('execa');
39
+ await execa('chmod', ['+x', path.join(scriptsDir, 'deploy.sh')]);
40
+ } catch (_) {}
41
+ }
42
+
43
+ // ─── Bash deploy ─────────────────────────────────────────────────────────────
44
+ function genDeployBash(s, L, M, config) {
45
+ return `#!/usr/bin/env bash
46
+ # ═══════════════════════════════════════════════════════════════════════════
47
+ # ${L} — Deploy Script (Linux / macOS)
48
+ # Generated by create-odoo-module — https://create-odoo-module.dev
49
+ # ═══════════════════════════════════════════════════════════════════════════
50
+ set -euo pipefail
51
+
52
+ # ── Load environment ────────────────────────────────────────────────────────
53
+ if [[ -f ".env" ]]; then
54
+ set -a && source .env && set +a
55
+ else
56
+ echo "⚠ .env file not found. Copy .env.example to .env and fill in your credentials."
57
+ exit 1
58
+ fi
59
+
60
+ MODULE_NAME="${s}"
61
+ ODOO_URL="\${ODOO_URL:-http://localhost:8069}"
62
+ ODOO_DB="\${ODOO_DB:-odoo}"
63
+ ODOO_USER="\${ODOO_USER:-admin}"
64
+ ODOO_PASSWORD="\${ODOO_PASSWORD:-admin}"
65
+ ADDONS_PATH="\${ODOO_ADDONS_PATH:-/opt/odoo/custom-addons}"
66
+ SERVICE="\${ODOO_SERVICE:-odoo}"
67
+
68
+ # ── Colors ──────────────────────────────────────────────────────────────────
69
+ RED='\\033[0;31m'; GREEN='\\033[0;32m'; YELLOW='\\033[1;33m'
70
+ CYAN='\\033[0;36m'; BOLD='\\033[1m'; RESET='\\033[0m'
71
+
72
+ info() { echo -e " \${CYAN}ℹ\${RESET} \$1"; }
73
+ success() { echo -e " \${GREEN}✔\${RESET} \$1"; }
74
+ warn() { echo -e " \${YELLOW}⚠\${RESET} \$1"; }
75
+ error() { echo -e " \${RED}✗\${RESET} \$1"; exit 1; }
76
+ header() { echo -e "\\n\${BOLD}\${CYAN}\$1\${RESET}\\n"; }
77
+
78
+ header "Deploying \${MODULE_NAME} → \${ODOO_URL}"
79
+
80
+ # ── Step 1: Validate source ──────────────────────────────────────────────────
81
+ if [[ ! -d "./odoo_module" ]]; then
82
+ error "odoo_module/ directory not found. Run this script from the project root."
83
+ fi
84
+ success "Source validated"
85
+
86
+ # ── Step 2: Copy files ───────────────────────────────────────────────────────
87
+ info "Copying module to \${ADDONS_PATH}/\${MODULE_NAME} ..."
88
+ if [[ -w "\${ADDONS_PATH}" ]]; then
89
+ cp -r ./odoo_module "\${ADDONS_PATH}/\${MODULE_NAME}"
90
+ else
91
+ sudo cp -r ./odoo_module "\${ADDONS_PATH}/\${MODULE_NAME}"
92
+ fi
93
+ success "Module files copied"
94
+
95
+ # ── Step 3: Restart Odoo ─────────────────────────────────────────────────────
96
+ info "Restarting Odoo service (\${SERVICE}) ..."
97
+ if systemctl is-active --quiet "\${SERVICE}" 2>/dev/null; then
98
+ sudo systemctl restart "\${SERVICE}"
99
+ sleep 5
100
+ success "Odoo restarted"
101
+ else
102
+ warn "Service '\${SERVICE}' not found or not running — skipping restart"
103
+ fi
104
+
105
+ # ── Step 4: Install / upgrade module ─────────────────────────────────────────
106
+ info "Upgrading module in Odoo database '\${ODOO_DB}' ..."
107
+ python3 - <<PYTHON
108
+ import sys
109
+ try:
110
+ import xmlrpc.client as rpc
111
+ url, db, user, pwd = "${'"'}${M}${'"'}".split(':')[0], '${M}'.split(':')[0], '${s}', '${s}'
112
+ url, db = "\${ODOO_URL}", "\${ODOO_DB}"
113
+ user, pwd = "\${ODOO_USER}", "\${ODOO_PASSWORD}"
114
+
115
+ common = rpc.ServerProxy(f'{url}/xmlrpc/2/common')
116
+ uid = common.authenticate(db, user, pwd, {})
117
+ if not uid:
118
+ print(" ✗ Authentication failed. Check ODOO_USER / ODOO_PASSWORD in .env")
119
+ sys.exit(1)
120
+
121
+ models = rpc.ServerProxy(f'{url}/xmlrpc/2/object')
122
+ mod_ids = models.execute_kw(db, uid, pwd,
123
+ 'ir.module.module', 'search',
124
+ [[['name', '=', '${s}']]]
125
+ )
126
+ if mod_ids:
127
+ models.execute_kw(db, uid, pwd,
128
+ 'ir.module.module', 'button_immediate_upgrade',
129
+ [mod_ids]
130
+ )
131
+ print(" ✔ Module upgraded successfully")
132
+ else:
133
+ models.execute_kw(db, uid, pwd,
134
+ 'ir.module.module', 'update_list', []
135
+ )
136
+ mod_ids = models.execute_kw(db, uid, pwd,
137
+ 'ir.module.module', 'search',
138
+ [[['name', '=', '${s}']]]
139
+ )
140
+ if mod_ids:
141
+ models.execute_kw(db, uid, pwd,
142
+ 'ir.module.module', 'button_immediate_install',
143
+ [mod_ids]
144
+ )
145
+ print(" ✔ Module installed successfully")
146
+ else:
147
+ print(" ⚠ Module not found in Odoo registry — check addons path config")
148
+ except Exception as e:
149
+ print(f" ✗ {e}")
150
+ sys.exit(1)
151
+ PYTHON
152
+
153
+ # ── Done ─────────────────────────────────────────────────────────────────────
154
+ header "Deployment Complete"
155
+ echo -e " Module : \${BOLD}\${MODULE_NAME}\${RESET}"
156
+ echo -e " Odoo : \${CYAN}\${ODOO_URL}\${RESET}"
157
+ echo -e " DB : \${ODOO_DB}\\n"
158
+ `;
159
+ }
160
+
161
+ // ─── PowerShell deploy ───────────────────────────────────────────────────────
162
+ function genDeployPowershell(s, L, M, config) {
163
+ return `# ═══════════════════════════════════════════════════════════════════════════
164
+ # ${L} — Deploy Script (Windows PowerShell)
165
+ # Generated by create-odoo-module — https://create-odoo-module.dev
166
+ # ═══════════════════════════════════════════════════════════════════════════
167
+ param(
168
+ [switch]$Force
169
+ )
170
+ Set-StrictMode -Version Latest
171
+ $ErrorActionPreference = "Stop"
172
+
173
+ # ── Load .env ──────────────────────────────────────────────────────────────
174
+ $envFile = Join-Path $PSScriptRoot "..\\.env"
175
+ if (-not (Test-Path $envFile)) {
176
+ Write-Error "ERROR: .env file not found. Copy .env.example → .env"
177
+ exit 1
178
+ }
179
+ Get-Content $envFile | ForEach-Object {
180
+ if ($_ -match "^([^#][^=]*)=(.*)$") {
181
+ [System.Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim())
182
+ }
183
+ }
184
+
185
+ $ModuleName = "${s}"
186
+ $OdooUrl = $Env:ODOO_URL ?? "http://localhost:8069"
187
+ $OdooDb = $Env:ODOO_DB ?? "odoo"
188
+ $OdooUser = $Env:ODOO_USER ?? "admin"
189
+ $OdooPassword = $Env:ODOO_PASSWORD ?? "admin"
190
+ $AddonsPath = $Env:ODOO_ADDONS_PATH ?? "C:\\odoo\\custom-addons"
191
+
192
+ Write-Host ""
193
+ Write-Host " Deploying $ModuleName → $OdooUrl" -ForegroundColor Cyan
194
+ Write-Host ""
195
+
196
+ # ── Copy files ─────────────────────────────────────────────────────────────
197
+ $src = Join-Path $PSScriptRoot "..\\odoo_module"
198
+ $dest = Join-Path $AddonsPath $ModuleName
199
+ Write-Host " Copying module to $dest..." -ForegroundColor Yellow
200
+ Copy-Item -Path $src -Destination $dest -Recurse -Force
201
+ Write-Host " ✔ Module files copied" -ForegroundColor Green
202
+
203
+ # ── Upgrade via XML-RPC ────────────────────────────────────────────────────
204
+ Write-Host " Upgrading module in Odoo..." -ForegroundColor Yellow
205
+ $pyScript = @"
206
+ import xmlrpc.client as rpc, sys
207
+ url, db, user, pwd = '$OdooUrl', '$OdooDb', '$OdooUser', '$OdooPassword'
208
+ try:
209
+ uid = rpc.ServerProxy(f'{url}/xmlrpc/2/common').authenticate(db, user, pwd, {})
210
+ if not uid:
211
+ print('Auth failed'); sys.exit(1)
212
+ m = rpc.ServerProxy(f'{url}/xmlrpc/2/object')
213
+ ids = m.execute_kw(db,uid,pwd,'ir.module.module','search',[[['name','=','$ModuleName']]])
214
+ m.execute_kw(db,uid,pwd,'ir.module.module','button_immediate_upgrade',[ids])
215
+ print('OK')
216
+ except Exception as e:
217
+ print(f'ERR: {e}'); sys.exit(1)
218
+ "@
219
+ $result = python3 -c $pyScript
220
+ if ($result -eq "OK") {
221
+ Write-Host " ✔ Module upgraded successfully" -ForegroundColor Green
222
+ } else {
223
+ Write-Warning " ⚠ $result"
224
+ }
225
+
226
+ Write-Host ""
227
+ Write-Host " ✔ Deployment complete!" -ForegroundColor Green
228
+ Write-Host " Odoo: $OdooUrl" -ForegroundColor Cyan
229
+ Write-Host ""
230
+ `;
231
+ }
232
+
233
+ // ─── Docker Compose ──────────────────────────────────────────────────────────
234
+ function genDockerCompose(s, config) {
235
+ return `# Docker Compose — Local Odoo development environment
236
+ # Generated by create-odoo-module — https://create-odoo-module.dev
237
+ #
238
+ # Usage:
239
+ # docker-compose up -d Start services
240
+ # docker-compose down Stop services
241
+ # docker-compose logs -f odoo Follow Odoo logs
242
+ # docker exec -it odoo_dev bash Enter Odoo container
243
+
244
+ version: '3.8'
245
+
246
+ services:
247
+
248
+ # ── PostgreSQL ────────────────────────────────────────────────────────────
249
+ db:
250
+ image: postgres:15-alpine
251
+ container_name: ${s}_db
252
+ restart: unless-stopped
253
+ environment:
254
+ POSTGRES_USER: odoo
255
+ POSTGRES_PASSWORD: odoo
256
+ POSTGRES_DB: odoo
257
+ volumes:
258
+ - pgdata:/var/lib/postgresql/data
259
+ ports:
260
+ - "5432:5432"
261
+ healthcheck:
262
+ test: ["CMD-SHELL", "pg_isready -U odoo"]
263
+ interval: 10s
264
+ timeout: 5s
265
+ retries: 5
266
+
267
+ # ── Odoo ─────────────────────────────────────────────────────────────────
268
+ odoo:
269
+ image: odoo:${config.odooVersion}
270
+ container_name: ${s}_odoo
271
+ restart: unless-stopped
272
+ depends_on:
273
+ db:
274
+ condition: service_healthy
275
+ ports:
276
+ - "8069:8069"
277
+ - "8072:8072" # Long-polling
278
+ volumes:
279
+ - ./odoo_module:/mnt/extra-addons/${s}
280
+ - odoo-data:/var/lib/odoo
281
+ - ./scripts/odoo.conf:/etc/odoo/odoo.conf:ro
282
+ environment:
283
+ HOST: db
284
+ USER: odoo
285
+ PASSWORD: odoo
286
+ command: >
287
+ odoo
288
+ --db_host=db
289
+ --db_port=5432
290
+ --db_user=odoo
291
+ --db_password=odoo
292
+ --addons-path=/usr/lib/python3/dist-packages/odoo/addons,/mnt/extra-addons
293
+ --dev=all
294
+ --log-level=info
295
+
296
+ volumes:
297
+ pgdata:
298
+ odoo-data:
299
+ `;
300
+ }
301
+
302
+ // ─── GitHub Actions CI ───────────────────────────────────────────────────────
303
+ function genGithubActions(s, L, M, config) {
304
+ return `name: ${L} CI
305
+
306
+ on:
307
+ push:
308
+ branches: [ main, develop ]
309
+ pull_request:
310
+ branches: [ main ]
311
+
312
+ jobs:
313
+ # ── Odoo Python tests ─────────────────────────────────────────────────────
314
+ odoo-test:
315
+ name: Odoo Module Tests (Python)
316
+ runs-on: ubuntu-22.04
317
+
318
+ services:
319
+ postgres:
320
+ image: postgres:15
321
+ env:
322
+ POSTGRES_USER: odoo
323
+ POSTGRES_PASSWORD: odoo
324
+ POSTGRES_DB: odoo_test
325
+ ports: ["5432:5432"]
326
+ options: >-
327
+ --health-cmd pg_isready
328
+ --health-interval 10s
329
+ --health-timeout 5s
330
+ --health-retries 5
331
+
332
+ steps:
333
+ - uses: actions/checkout@v4
334
+
335
+ - name: Set up Python
336
+ uses: actions/setup-python@v5
337
+ with:
338
+ python-version: '3.11'
339
+
340
+ - name: Install Python dependencies
341
+ run: |
342
+ pip install pytest flake8
343
+
344
+ - name: Lint Python code
345
+ run: |
346
+ flake8 odoo_module/ --max-line-length=120 --exclude=__pycache__
347
+
348
+ - name: Run Odoo tests
349
+ run: |
350
+ echo "Odoo integration tests require a running Odoo instance."
351
+ echo "Configure your Odoo test environment here."
352
+ # Uncomment and configure for full Odoo testing:
353
+ # run: |
354
+ # ./odoo-bin test -d odoo_test --test-tags ${s} --stop-after-init
355
+
356
+ ${config.withUi ? `
357
+ # ── Flutter tests ──────────────────────────────────────────────────────────
358
+ flutter-test:
359
+ name: Flutter App Tests (Dart)
360
+ runs-on: ubuntu-latest
361
+
362
+ steps:
363
+ - uses: actions/checkout@v4
364
+
365
+ - name: Set up Flutter
366
+ uses: subosito/flutter-action@v2
367
+ with:
368
+ flutter-version: '3.19.0'
369
+ channel: 'stable'
370
+
371
+ - name: Install Flutter dependencies
372
+ working-directory: flutter_app
373
+ run: flutter pub get
374
+
375
+ - name: Analyze Dart code
376
+ working-directory: flutter_app
377
+ run: flutter analyze
378
+
379
+ - name: Run Flutter tests
380
+ working-directory: flutter_app
381
+ run: flutter test --coverage
382
+
383
+ - name: Build APK (debug)
384
+ working-directory: flutter_app
385
+ run: flutter build apk --debug
386
+ ` : ''}
387
+ `;
388
+ }
389
+
390
+ module.exports = { generateDeployScripts };