@cerema/cadriciel 1.6.2-beta → 1.6.5

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.
@@ -1,94 +1,226 @@
1
1
  module.exports = (args) => {
2
- const { exec } = require('child_process');
3
- const Listr = require('listr');
4
- const chalk = require('chalk-v2');
5
- const os = require('os');
6
- const platform = os.platform();
7
- const checkInstallation = (command, postProcess = (output) => output) => {
8
- return new Promise((resolve, reject) => {
9
- exec(command, (error, stdout) => {
10
- if (error) {
11
- reject(new Error('Not installed'));
12
- } else {
13
- resolve(postProcess(stdout.trim()));
14
- }
15
- });
16
- });
17
- };
18
- return {
19
- info: {
20
- title: 'doctor',
21
- description: `Affichage des pré-requis du cadriciel.`,
22
- },
23
- start: () => {
24
- console.log(' ');
25
-
26
- console.log(' 🏥 ' + chalk.bold('Pré-requis globaux'));
27
- console.log(' ');
28
- const myTasks = [
2
+ const { exec } = require('child_process');
3
+ const Listr = require('listr');
4
+ const chalk = require('chalk-v2');
5
+ const os = require('os');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const platform = os.platform();
9
+ const checkInstallation = (command, postProcess = (output) => output) => {
10
+ return new Promise((resolve, reject) => {
11
+ exec(command, (error, stdout) => {
12
+ if (error) {
13
+ reject(new Error('Not installed'));
14
+ } else {
15
+ resolve(postProcess(stdout.trim()));
16
+ }
17
+ });
18
+ });
19
+ };
20
+ const checkOneOfInstallations = (candidates = [], label = 'commande') => {
21
+ const tryCandidate = (index) => {
22
+ if (index >= candidates.length) {
23
+ return Promise.reject(new Error(`${label} non détecté`));
24
+ }
25
+ const candidate = candidates[index];
26
+ const postProcess =
27
+ candidate.postProcess ||
28
+ ((output) => `${candidate.label || candidate.command}: ${output}`);
29
+ return checkInstallation(candidate.command, postProcess).catch(() =>
30
+ tryCandidate(index + 1)
31
+ );
32
+ };
33
+ return tryCandidate(0);
34
+ };
35
+ const PACKAGE_MANAGERS = [
29
36
  {
30
- title: 'Homebrew',
31
- task: () => checkInstallation('brew --version'),
37
+ id: 'bun',
38
+ displayName: 'Bun',
39
+ command: 'bun --version',
40
+ detectors: ['bun.lock', 'bun.lockb'],
32
41
  },
33
42
  {
34
- title: 'Pnpm',
35
- task: () => checkInstallation('pnpm -v'),
43
+ id: 'pnpm',
44
+ displayName: 'pnpm',
45
+ command: 'pnpm -v',
46
+ detectors: ['pnpm-lock.yaml', 'pnpm-lock.yml'],
36
47
  },
37
48
  {
38
- title: 'Git',
39
- task: () => checkInstallation('git --version'),
49
+ id: 'yarn',
50
+ displayName: 'Yarn',
51
+ command: 'yarn -v',
52
+ detectors: ['yarn.lock'],
40
53
  },
41
54
  {
42
- title: 'Java',
43
- task: () => checkInstallation('java --version'),
55
+ id: 'npm',
56
+ displayName: 'npm',
57
+ command: 'npm -v',
58
+ detectors: ['package-lock.json'],
59
+ },
60
+ ];
61
+ const findCadricielContext = () => {
62
+ let currentPath = process.cwd();
63
+ const rootPath = path.parse(currentPath).root;
64
+ while (true) {
65
+ const versionPath = path.join(currentPath, '.cadriciel', 'version.json');
66
+ if (fs.existsSync(versionPath)) {
67
+ try {
68
+ const version = JSON.parse(fs.readFileSync(versionPath, 'utf8'));
69
+ return {
70
+ architecture: typeof version.name === 'string' ? version.name : null,
71
+ projectRoot: currentPath,
72
+ };
73
+ } catch (error) {
74
+ return {
75
+ architecture: null,
76
+ projectRoot: currentPath,
77
+ };
78
+ }
79
+ }
80
+ if (currentPath === rootPath) break;
81
+ currentPath = path.dirname(currentPath);
82
+ }
83
+ return {
84
+ architecture: null,
85
+ projectRoot: null,
86
+ };
87
+ };
88
+ const detectPackageManager = (projectRoot) => {
89
+ const searchRoot = projectRoot || process.cwd();
90
+ const packageJsonPath = path.join(searchRoot, 'package.json');
91
+ if (fs.existsSync(packageJsonPath)) {
92
+ try {
93
+ const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
94
+ if (pkgJson.packageManager && typeof pkgJson.packageManager === 'string') {
95
+ const requested = pkgJson.packageManager.split('@')[0].trim().toLowerCase();
96
+ const pm = PACKAGE_MANAGERS.find((el) => el.id === requested);
97
+ if (pm) return pm;
98
+ }
99
+ } catch (error) { }
100
+ }
101
+ for (const pm of PACKAGE_MANAGERS) {
102
+ if (
103
+ pm.detectors.some((fileName) =>
104
+ fs.existsSync(path.join(searchRoot, fileName))
105
+ )
106
+ ) {
107
+ return pm;
108
+ }
109
+ }
110
+ return PACKAGE_MANAGERS.find((el) => el.id === 'npm');
111
+ };
112
+ const createNodeArchitectureTasks = (projectRoot) => {
113
+ const detectedManager = detectPackageManager(projectRoot);
114
+ const tasks = [
115
+ {
116
+ title: 'Node ou Bun',
117
+ task: () =>
118
+ checkOneOfInstallations(
119
+ [
120
+ { command: 'node -v', label: 'Node' },
121
+ { command: 'bun --version', label: 'Bun' },
122
+ ],
123
+ 'Node ou Bun'
124
+ ),
125
+ },
126
+ {
127
+ title: 'npm ou Bun',
128
+ task: () =>
129
+ checkOneOfInstallations(
130
+ [
131
+ { command: 'npm -v', label: 'npm' },
132
+ { command: 'bun --version', label: 'Bun' },
133
+ ],
134
+ 'npm ou Bun'
135
+ ),
136
+ },
137
+ ];
138
+ if (detectedManager) {
139
+ tasks.push({
140
+ title: `Gestionnaire (${detectedManager.displayName})`,
141
+ task: () => checkInstallation(detectedManager.command),
142
+ });
143
+ }
144
+ tasks.push(
145
+ {
146
+ title: 'Docker',
147
+ task: () => checkInstallation('docker ps'),
148
+ },
149
+ {
150
+ title: 'Docker Compose',
151
+ task: () => checkInstallation('docker-compose --version'),
152
+ }
153
+ );
154
+ return tasks;
155
+ };
156
+ const runArchitectureDoctor = ({ architecture, projectRoot }) => {
157
+ if (!architecture) {
158
+ if (!projectRoot) {
159
+ console.log(' ');
160
+ console.log(
161
+ chalk.yellow(
162
+ " ⚠️ Impossible de détecter l'architecture du cadriciel (.cadriciel/version.json introuvable)."
163
+ )
164
+ );
165
+ }
166
+ return Promise.resolve();
167
+ }
168
+ const normalized = architecture.toLowerCase();
169
+ if (normalized === 'node') {
170
+ console.log(' ');
171
+ console.log(' 🧱 ' + chalk.bold('Pré-requis architecture Node'));
172
+ console.log(' ');
173
+ const nodeTasks = new Listr(createNodeArchitectureTasks(projectRoot), {
174
+ concurrent: true,
175
+ exitOnError: false,
176
+ });
177
+ return nodeTasks.run().catch(() => { });
178
+ }
179
+ console.log(' ');
180
+ console.log(' 🧱 ' + chalk.bold('Pré-requis architecture'));
181
+ console.log(' ');
182
+ console.log(
183
+ chalk.yellow(
184
+ ` Architecture '${architecture}' détectée mais non prise en charge par ce docteur.`
185
+ )
186
+ );
187
+ return Promise.resolve();
188
+ };
189
+ return {
190
+ info: {
191
+ title: 'doctor',
192
+ description: `Affichage des pré-requis du cadriciel.`,
44
193
  },
45
- ];
46
- if (platform === 'linux ') myTasks.splice(0, 1);
47
- if (platform === 'win32') myTasks.splice(0, 1);
194
+ start: () => {
195
+ console.log(' ');
48
196
 
49
- const tasks = new Listr(myTasks, {
50
- concurrent: true,
51
- exitOnError: false,
52
- });
197
+ console.log(' 🏥 ' + chalk.bold('Pré-requis globaux'));
198
+ console.log(' ');
199
+ const myTasks = [
200
+ {
201
+ title: 'Git',
202
+ task: () => checkInstallation('git --version'),
203
+ },
204
+ {
205
+ title: 'Java',
206
+ task: () => checkInstallation('java --version'),
207
+ },
208
+ ];
209
+ if (platform === 'linux') myTasks.splice(0, 1);
210
+ if (platform === 'win32') myTasks.splice(0, 1);
53
211
 
54
- const dockerTasks = new Listr(
55
- [
56
- {
57
- title: 'Docker',
58
- task: () => checkInstallation('docker ps'),
59
- },
60
- {
61
- title: 'Docker Compose',
62
- task: () => checkInstallation('docker-compose --version'),
63
- },
64
- ],
65
- { concurrent: true, exitOnError: false }
66
- );
212
+ const tasks = new Listr(myTasks, {
213
+ concurrent: true,
214
+ exitOnError: false,
215
+ });
67
216
 
68
- tasks
69
- .run()
70
- .then(() => {
71
- console.log(' ');
72
- console.log(
73
- ' 📦 ' +
74
- chalk.bold('Pré-requis Docker') +
75
- ' (si vous utilisez docker)'
76
- );
77
- console.log(' ');
78
- dockerTasks.run().then(()=>{
79
- }).catch((err) => {});
80
- })
81
- .catch((err) => {
82
- console.log(' ');
83
- console.log(
84
- ' 📦 ' +
85
- chalk.bold('Pré-requis Docker') +
86
- ' (si vous utilisez docker)'
87
- );
88
- console.log(' ');
89
- dockerTasks.run().then(()=>{
90
- }).catch((err) => {});
91
- });
92
- },
93
- };
217
+ const architectureContext = findCadricielContext();
218
+
219
+ tasks
220
+ .run()
221
+ .catch(() => { })
222
+ .then(() => runArchitectureDoctor(architectureContext))
223
+ .catch(() => { });
224
+ },
225
+ };
94
226
  };
@@ -1,252 +1,49 @@
1
1
  module.exports = (args) => {
2
- const { promisify } = require('util');
3
- const { exec } = require('child_process');
4
- const execPromise = promisify(exec);
2
+ const path = require('path');
5
3
  const fs = require('fs');
6
- const ora = require('ora');
4
+ const fse = require('fs-extra');
7
5
  const chalk = require('chalk-v2');
8
- const log = require('log-beautify');
9
- const inquirer = require('inquirer');
10
- const path = require('path');
11
- const cliProgress = require('cli-progress');
12
- const userHome = require('os').homedir();
13
- const error = require(path.join('..', '..', 'lib', 'message')).error;
14
- const { getTemplates } = require(path.join('..', '..', 'lib', 'util'));
15
- const link = (url, name) => {
16
- if (!name) name = url;
17
- if (url.includes('localhost')) url = 'http://' + url + '/';
18
- else url = 'https://' + url + '/';
19
- return (
20
- '\u001b[36m\u001b]8;;' +
21
- url +
22
- '\u0007' +
23
- name +
24
- '\u001b]8;;\u0007\u001b[0m\n'
25
- );
26
- };
27
- const sshtemplate = `
28
- # cadriciel -- 87c7dfbf-172a-4084-a862-4a23f35a5b79 --
29
- Host cadriciel
30
- HostName gitlab.cerema.fr
31
- User git
32
- IdentityFile ~/.cadriciel/id_rsa
33
- IdentitiesOnly yes
34
- # -----------------------------------------------------
35
- `;
36
- const CadricielAPI = require(path.join('..', '..', 'lib', 'cadriciel'));
37
- const cadriciel = new CadricielAPI();
38
- var templates = [];
39
- const progress = async (bar1, response, cb) => {
40
- try {
41
- const p = await cadriciel.get(`status/jobs/projects/${response.prj.id}`);
42
- bar1.update(p.progress);
43
- if (p.progress < 100)
44
- setTimeout(() => {
45
- progress(bar1, response, cb);
46
- }, 1000);
47
- else {
48
- bar1.stop();
49
- cb();
50
- }
51
- } catch (e) {
52
- error('Erreur lors de la création du projet');
6
+
7
+ const sourceDir = path.resolve(__dirname, '..', 'assets', 'docker');
8
+
9
+ const copyDockerDirectory = () => {
10
+ const destinationDir = path.resolve(process.cwd(), 'docker');
11
+ if (!fs.existsSync(sourceDir)) {
12
+ console.error(
13
+ chalk.red("Répertoire source 'assets/docker' introuvable dans le CLI.")
14
+ );
15
+ process.exitCode = 1;
16
+ return;
53
17
  }
54
- };
55
- const updatePK = async () => {
56
- try {
57
- var pk = await cadriciel.get(`privatekey`);
58
- const pkey = Buffer.from(pk.private_key, 'base64').toString();
59
- fs.writeFileSync(userHome + '/.cadriciel/id_rsa', pkey);
60
- fs.chmodSync(userHome + '/.cadriciel/id_rsa', 0o600);
61
- try {
62
- fs.mkdirSync(userHome + '/.ssh');
63
- } catch (e) {}
64
- try {
65
- var ssh = fs.readFileSync(userHome + '/.ssh/config', 'utf-8');
66
- } catch (e) {
67
- var ssh = '';
68
- }
69
- if (!ssh.includes('87c7dfbf-172a-4084-a862-4a23f35a5b79 ')) {
70
- ssh += '\n\n' + sshtemplate;
71
- fs.writeFileSync(userHome + '/.ssh/config', ssh, { flag: 'a' });
72
- fs.chmodSync(userHome + '/.ssh/config', 0o600);
73
- }
74
- } catch (e) {
75
- console.log(e);
76
- error(
77
- "Une erreur s'est produite lors de la récupération de la clé privée"
18
+ if (fs.existsSync(destinationDir)) {
19
+ console.log(
20
+ chalk.yellow("Le répertoire 'docker' existe déjà dans ce projet.")
78
21
  );
22
+ return;
79
23
  }
80
- };
81
- const launch = async (answers) => {
82
- const data = {
83
- name: answers.project,
84
- title: answers.project,
85
- template: answers.template,
86
- group: 'PERSO',
87
- disabled: true,
88
- };
89
24
  try {
90
- var response = await cadriciel.post(`studio/projects`, data);
91
- } catch (e) {
92
- if (e.response.data.error == 'PROJECT_ALREADY_EXISTS')
93
- error(
94
- "Le nom du projet n'est pas disponible. Veuillez choisir un autre titre."
95
- );
96
- else error('Erreur lors de la création du projet');
97
- return process.exit(1);
25
+ fse.copySync(sourceDir, destinationDir);
26
+ console.log(
27
+ chalk.green("Le répertoire 'docker' a été copié dans votre projet.")
28
+ );
29
+ } catch (error) {
30
+ console.error(
31
+ chalk.red(
32
+ `Erreur lors de la copie du répertoire docker: ${error.message}`
33
+ )
34
+ );
35
+ process.exitCode = 1;
98
36
  }
99
- console.log(`${chalk.bold('\n 🚀 Création du projet en cours...')}\n`);
100
- const bar1 = new cliProgress.SingleBar(
101
- {},
102
- cliProgress.Presets.shades_classic
103
- );
104
- bar1.start(100, 0);
105
- progress(bar1, response, async () => {
106
- console.log(' ');
107
-
108
- const step1 = ora('📥 Téléchargement du projet en cours...').start();
109
- try {
110
- await updatePK();
111
-
112
- try {
113
- const git = await execPromise('git clone ' + response.prj.uri, {
114
- cwd: process.cwd(),
115
- });
116
- } catch (e) {
117
- step1.fail(chalk.red.bold(e.message.split('fatal :')[1]));
118
- process.exit(1);
119
- }
120
-
121
- step1.succeed(chalk.bold('Téléchargement OK.'));
122
- console.log(' ');
123
- const step2 = ora('📦 Installation des dépendances...').start();
124
- try {
125
- try {
126
- await execPromise('pnpm i', {
127
- cwd: process.cwd() + '/' + response.prj.title,
128
- });
129
- } catch (e) {
130
- try {
131
- await execPromise('yarn', {
132
- cwd: process.cwd() + '/' + response.prj.title,
133
- });
134
- } catch (e) {
135
- await execPromise('npm i', {
136
- cwd: process.cwd() + '/' + response.prj.title,
137
- });
138
- }
139
- }
140
-
141
- try {
142
- await execPromise(
143
- `git config --local user.email "${response.prj.owner.email}" && git config --local user.name "${response.prj.owner.name}" && git add --all && git checkout -b ${response.prj.owner.trigram} && git config pull.rebase true`,
144
- {
145
- cwd: process.cwd() + '/' + response.prj.title,
146
- }
147
- );
148
- step2.succeed(
149
- '🎉 ' + chalk.bold('Votre projet a été correctement installé')
150
- );
151
- console.log(' ');
152
- console.log(`
153
- ──────────────────────────────────────────────────────────────
154
- URL du projet : ${link(response.prj.url.split('https://')[1])}
155
-
156
- Vous trouverez votre projet dans le dossier :
157
-
158
- cd ${chalk.green(response.prj.title)}
159
-
160
- 🚀 ${chalk.bold("Pour lancer l'environnement de développement :")}
161
-
162
- ${chalk.green('cad start')}
163
-
164
- 🚦 ${chalk.bold("Pour arrêter l'environnement de développement :")}
165
-
166
- ${chalk.green('cad stop')}
167
-
168
- 💻 ${chalk.bold('Pour manager votre projet :')}
169
-
170
- 👉 ${link(
171
- global.CACHE_URI.studio.split('://')[1],
172
- global.CACHE_URI.studio.split('://')[1]
173
- )}
174
-
175
- ──────────────────────────────────────────────────────────────`);
176
- console.log(' ');
177
- } catch (e) {
178
- console.log(e);
179
- }
180
- } catch (e) {}
181
- } catch (e) {
182
- console.log(e);
183
- step1.fail(chalk.red('Déploiement échoué'));
184
- return process.exit(1);
185
- }
186
- });
187
37
  };
38
+
188
39
  return {
189
40
  info: {
190
- title: 'completion',
191
- description: `Démarrage d'un projet Cadriciel`,
41
+ title: 'init',
42
+ label: 'docker',
43
+ description: 'Initialisation du répertoire docker du projet',
192
44
  },
193
- start: async () => {
194
- const spinner = ora('Veuillez patienter un instant...').start();
195
- try {
196
- templates = await getTemplates();
197
- } catch (e) {
198
- console.log(e);
199
- spinner.stop();
200
- error('Mise à jour impossible... Vérifier votre connexion internet');
201
- return process.exit(1);
202
- }
203
- spinner.stop();
204
- var tpl = [];
205
- if (!templates) return process.exit(1);
206
- for (let i = 0; i < templates.length; i++) tpl.push(templates[i].title);
207
- const questions = [
208
- {
209
- type: 'input',
210
- name: 'project',
211
- message: 'Nom du projet',
212
- validate: (value) => {
213
- if (value === '') return false;
214
- else return true;
215
- },
216
- },
217
- {
218
- type: 'list',
219
- name: 'template',
220
- message: 'Choisissez le modèle de cadriciel',
221
- choices: tpl,
222
- },
223
- ];
224
-
225
- if (tpl.length == 1) questions.splice(1, 1);
226
- if (process.argv[1]) {
227
- if (questions.length == 1)
228
- return launch({
229
- project: process.argv[1],
230
- template: templates[0].dir,
231
- });
232
- }
233
- console.log(
234
- '\n😃 ' + chalk.bold('Tout grand projet commence par un nom !\n')
235
- );
236
- inquirer
237
- .prompt(questions)
238
- .then((answers) => {
239
- if (!answers.template) answers.template = templates[0].dir;
240
- else {
241
- for (let i = 0; i < templates.length; i++)
242
- if (templates[i].title == answers.template)
243
- answers.template = templates[i].dir;
244
- }
245
- launch(answers);
246
- })
247
- .catch((error) => {
248
- log.error(error);
249
- });
45
+ start: () => {
46
+ copyDockerDirectory();
250
47
  },
251
48
  };
252
49
  };