From 11fd119f7b77de6beebab48c1242eec4dff80400 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 2 Aug 2025 20:53:17 +0200 Subject: [PATCH 1/4] feat: ask about podman and skylab or satellite and generate templates --- src/services/dev/_runner.services.ts | 52 +++++++++++++++++++--------- src/types/emulator.ts | 8 +++-- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/services/dev/_runner.services.ts b/src/services/dev/_runner.services.ts index 8de7d181..e8592172 100644 --- a/src/services/dev/_runner.services.ts +++ b/src/services/dev/_runner.services.ts @@ -12,7 +12,12 @@ import { EMULATOR_PORT_SERVER, EMULATOR_SKYLAB } from '../../constants/emulator.constants'; -import {type CliEmulatorConfig, type CliEmulatorDerivedConfig} from '../../types/emulator'; +import { + type CliEmulatorConfig, + type CliEmulatorDerivedConfig, + EmulatorRunnerType, + EmulatorType +} from '../../types/emulator'; import {isHeadless} from '../../utils/process.utils'; import {confirmAndExit} from '../../utils/prompt.utils'; import { @@ -68,14 +73,8 @@ export const stopContainer = async () => { await stopEmulator({config}); }; -const initJunoConfigFile = async () => { - await confirmAndExit(`Your project needs a config file for Juno. Should we create one now?`); - - await initConfigNoneInteractive(); -}; - -const promptEmulatorType = async (): Promise<{emulatorType: 'skylab' | 'satellite'}> => { - const {emulatorType}: {emulatorType: 'skylab' | 'satellite' | undefined} = await prompts({ +const promptEmulatorType = async (): Promise<{emulatorType: Exclude}> => { + const {emulatorType}: {emulatorType: Exclude | undefined} = await prompts({ type: 'select', name: 'emulatorType', message: 'What kind of emulator would you like to run locally?', @@ -84,7 +83,7 @@ const promptEmulatorType = async (): Promise<{emulatorType: 'skylab' | 'satellit title: `Production-like setup with Console UI and known services`, value: `skylab` }, - {title: `Minimal setup without any UI`, value: `satellite`} + {title: `Minimal headless setup`, value: `satellite`} ] }); @@ -93,6 +92,25 @@ const promptEmulatorType = async (): Promise<{emulatorType: 'skylab' | 'satellit return {emulatorType}; }; +const promptRunnerType = async (): Promise<{runnerType: EmulatorRunnerType}> => { + const {runnerType}: {runnerType: EmulatorRunnerType | undefined} = await prompts({ + type: 'select', + name: 'runnerType', + message: 'Which container runtime would you like to use?', + choices: [ + { + title: 'Docker', + value: `docker` + }, + {title: `Podman`, value: `podman`} + ] + }); + + assertAnswerCtrlC(runnerType); + + return {runnerType}; +}; + const assertAndInitConfig = async () => { const configExist = await junoConfigExist(); @@ -100,15 +118,17 @@ const assertAndInitConfig = async () => { return; } + await initConfigFile(); +}; + +const initConfigFile = async () => { const {emulatorType} = await promptEmulatorType(); - await initConfigFile(emulatorType === 'skylab'); -}; + const {runner} = await promptRunnerType(); -const initConfigFile = async (_skylab: boolean) => { - // TODO: if not skyLab, emulator satellite {} - // or remove question? - await initJunoConfigFile(); + await confirmAndExit(`Proceed with creating the Juno config file using these settings?`); + + await initConfigNoneInteractive(); }; const startEmulator = async ({config: extendedConfig}: {config: CliEmulatorConfig}) => { diff --git a/src/types/emulator.ts b/src/types/emulator.ts index 094d6e62..173a5eb0 100644 --- a/src/types/emulator.ts +++ b/src/types/emulator.ts @@ -1,9 +1,13 @@ import type {EmulatorConfig, EmulatorRunner} from '@junobuild/config'; +export type EmulatorType = 'skylab' | 'satellite' | 'console'; + +export type EmulatorRunnerType = EmulatorRunner['type']; + export interface CliEmulatorDerivedConfig { containerName: string; - runner: EmulatorRunner['type']; - emulatorType: 'skylab' | 'satellite' | 'console'; + runner: EmulatorRunnerType; + emulatorType: EmulatorType; targetDeploy: string; } From 8b4c83ae9a7c1f9a8059fddd079f95962b3a7410 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 2 Aug 2025 21:19:12 +0200 Subject: [PATCH 2/4] feat: create config with podman or docker --- .prettierignore | 1 + eslint.config.mjs | 1 - src/configs/juno.config.ts | 24 ++++++++-- src/constants/templates.constants.ts | 4 ++ src/services/dev/_runner.services.ts | 44 +++++++++++-------- src/services/init.services.ts | 8 +++- src/types/emulator.ts | 4 +- templates/init/juno.runner.config.js | 18 ++++++++ templates/init/juno.runner.config.ts | 17 +++++++ .../init/juno.runner.predeploy.config.js | 19 ++++++++ .../init/juno.runner.predeploy.config.ts | 18 ++++++++ tsconfig.json | 3 +- 12 files changed, 134 insertions(+), 27 deletions(-) create mode 100644 templates/init/juno.runner.config.js create mode 100644 templates/init/juno.runner.config.ts create mode 100644 templates/init/juno.runner.predeploy.config.js create mode 100644 templates/init/juno.runner.predeploy.config.ts diff --git a/.prettierignore b/.prettierignore index 1521c8b7..4953e178 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ dist +templates/init diff --git a/eslint.config.mjs b/eslint.config.mjs index 2d12b63f..f647db27 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -26,7 +26,6 @@ export default [ } } }, - { rules: { 'no-console': 'off', diff --git a/src/configs/juno.config.ts b/src/configs/juno.config.ts index 5be7ead6..97efc2f2 100644 --- a/src/configs/juno.config.ts +++ b/src/configs/juno.config.ts @@ -15,10 +15,13 @@ import {JUNO_CONFIG_FILENAME} from '../constants/constants'; import { TEMPLATE_INIT_PATH, TEMPLATE_JUNO_PREDEPLOY_CONFIG_FILENAME, + TEMPLATE_RUNNER_CONFIG_FILENAME, + TEMPLATE_RUNNER_PREDEPLOY_CONFIG_FILENAME, TEMPLATE_SKYLAB_CONFIG_FILENAME, TEMPLATE_SKYLAB_PREDEPLOY_CONFIG_FILENAME } from '../constants/templates.constants'; import {type JunoConfigWithPlaceholder, type JunoConfigWithSatelliteId} from '../types/config'; +import {type EmulatorConfigWithoutConsole} from '../types/emulator'; import type {PackageManager} from '../types/pm'; import {readTemplateFile} from '../utils/fs.utils'; @@ -37,9 +40,11 @@ export const writeJunoConfigPlaceholder = async ({ config, configType, configPath, - pm + pm, + emulatorConfig }: {config: JunoConfigWithPlaceholder} & PartialConfigFile & { pm: PackageManager | undefined; + emulatorConfig?: EmulatorConfigWithoutConsole; }): Promise => { switch (configType) { case 'ts': @@ -50,14 +55,27 @@ export const writeJunoConfigPlaceholder = async ({ const withPredeploy = nonNullish(pm); + const templateFilename = nonNullish(emulatorConfig) + ? withPredeploy + ? TEMPLATE_RUNNER_PREDEPLOY_CONFIG_FILENAME + : TEMPLATE_RUNNER_CONFIG_FILENAME + : withPredeploy + ? TEMPLATE_SKYLAB_PREDEPLOY_CONFIG_FILENAME + : TEMPLATE_SKYLAB_CONFIG_FILENAME; + const template = await readTemplateFile({ - template: `${withPredeploy ? TEMPLATE_SKYLAB_PREDEPLOY_CONFIG_FILENAME : TEMPLATE_SKYLAB_CONFIG_FILENAME}.${configType}`, + template: `${templateFilename}.${configType}`, sourceFolder: TEMPLATE_INIT_PATH }); const content = template .replace('', source ?? DEPLOY_DEFAULT_SOURCE) - .replace('', pm === 'npm' ? 'npm run' : (pm ?? '')); + .replace('', pm === 'npm' ? 'npm run' : (pm ?? '')) + .replace('', emulatorConfig?.runner?.type ?? '') + .replace( + '', + nonNullish(emulatorConfig) ? ('satellite' in emulatorConfig ? 'satellite' : 'skylab') : '' + ); await writeFile(configPath ?? `${JUNO_CONFIG_FILENAME}.${configType}`, content, 'utf-8'); break; diff --git a/src/constants/templates.constants.ts b/src/constants/templates.constants.ts index b7c32a33..0b896bda 100644 --- a/src/constants/templates.constants.ts +++ b/src/constants/templates.constants.ts @@ -1,5 +1,9 @@ export const TEMPLATE_INIT_PATH = '../templates/init'; + export const TEMPLATE_SKYLAB_CONFIG_FILENAME = `juno.skylab.config`; export const TEMPLATE_JUNO_PREDEPLOY_CONFIG_FILENAME = `juno.predeploy.config`; export const TEMPLATE_SKYLAB_PREDEPLOY_CONFIG_FILENAME = `juno.skylab.predeploy.config`; + +export const TEMPLATE_RUNNER_CONFIG_FILENAME = `juno.runner.config`; +export const TEMPLATE_RUNNER_PREDEPLOY_CONFIG_FILENAME = `juno.runner.predeploy.config`; diff --git a/src/services/dev/_runner.services.ts b/src/services/dev/_runner.services.ts index e8592172..9a5c0f38 100644 --- a/src/services/dev/_runner.services.ts +++ b/src/services/dev/_runner.services.ts @@ -15,8 +15,8 @@ import { import { type CliEmulatorConfig, type CliEmulatorDerivedConfig, - EmulatorRunnerType, - EmulatorType + type EmulatorRunnerType, + type EmulatorType } from '../../types/emulator'; import {isHeadless} from '../../utils/process.utils'; import {confirmAndExit} from '../../utils/prompt.utils'; @@ -73,19 +73,20 @@ export const stopContainer = async () => { await stopEmulator({config}); }; -const promptEmulatorType = async (): Promise<{emulatorType: Exclude}> => { - const {emulatorType}: {emulatorType: Exclude | undefined} = await prompts({ - type: 'select', - name: 'emulatorType', - message: 'What kind of emulator would you like to run locally?', - choices: [ - { - title: `Production-like setup with Console UI and known services`, - value: `skylab` - }, - {title: `Minimal headless setup`, value: `satellite`} - ] - }); +const promptEmulatorType = async (): Promise<{emulatorType: Exclude}> => { + const {emulatorType}: {emulatorType: Exclude | undefined} = + await prompts({ + type: 'select', + name: 'emulatorType', + message: 'What kind of emulator would you like to run locally?', + choices: [ + { + title: `Complete environment with Console and known services`, + value: `skylab` + }, + {title: `Minimal headless setup`, value: `satellite`} + ] + }); assertAnswerCtrlC(emulatorType); @@ -124,11 +125,16 @@ const assertAndInitConfig = async () => { const initConfigFile = async () => { const {emulatorType} = await promptEmulatorType(); - const {runner} = await promptRunnerType(); - - await confirmAndExit(`Proceed with creating the Juno config file using these settings?`); + const {runnerType} = await promptRunnerType(); - await initConfigNoneInteractive(); + await initConfigNoneInteractive({ + emulatorConfig: { + runner: { + type: runnerType + }, + ...(emulatorType === 'satellite' ? {satellite: {}} : {skylab: {}}) + } + }); }; const startEmulator = async ({config: extendedConfig}: {config: CliEmulatorConfig}) => { diff --git a/src/services/init.services.ts b/src/services/init.services.ts index 86bf398d..7fca7aa8 100644 --- a/src/services/init.services.ts +++ b/src/services/init.services.ts @@ -14,6 +14,7 @@ import { writeJunoConfigPlaceholder } from '../configs/juno.config'; import type {CliOrbiterConfig, CliSatelliteConfig} from '../types/cli.config'; +import {type EmulatorConfigWithoutConsole} from '../types/emulator'; import type {PackageManager} from '../types/pm'; import {detectPackageManager} from '../utils/pm.utils'; import {NEW_CMD_LINE} from '../utils/prompt.utils'; @@ -41,13 +42,16 @@ export type InitConfigParams = PartialConfigFile & {pm: PackageManager | undefin source: string; }; -export const initConfigNoneInteractive = async () => { +export const initConfigNoneInteractive = async ({ + emulatorConfig +}: {emulatorConfig?: EmulatorConfigWithoutConsole} = {}) => { const writeFn = async ({source, ...rest}: InitConfigParams) => { await writeJunoConfigPlaceholder({ ...rest, config: { satellite: {source} - } + }, + emulatorConfig }); }; diff --git a/src/types/emulator.ts b/src/types/emulator.ts index 173a5eb0..18963ffc 100644 --- a/src/types/emulator.ts +++ b/src/types/emulator.ts @@ -1,9 +1,11 @@ -import type {EmulatorConfig, EmulatorRunner} from '@junobuild/config'; +import type {EmulatorConfig, EmulatorConsole, EmulatorRunner} from '@junobuild/config'; export type EmulatorType = 'skylab' | 'satellite' | 'console'; export type EmulatorRunnerType = EmulatorRunner['type']; +export type EmulatorConfigWithoutConsole = Exclude; + export interface CliEmulatorDerivedConfig { containerName: string; runner: EmulatorRunnerType; diff --git a/templates/init/juno.runner.config.js b/templates/init/juno.runner.config.js new file mode 100644 index 00000000..58d34fad --- /dev/null +++ b/templates/init/juno.runner.config.js @@ -0,0 +1,18 @@ +import {defineConfig} from '@junobuild/config'; + +/** @type {import('@junobuild/config').JunoConfig} */ +export default defineConfig({ + satellite: { + ids: { + development: '', + production: '' + }, + source: '' + }, + emulator: { + runner: { + type: '' + }, + : {} + } +}); diff --git a/templates/init/juno.runner.config.ts b/templates/init/juno.runner.config.ts new file mode 100644 index 00000000..eef4a23e --- /dev/null +++ b/templates/init/juno.runner.config.ts @@ -0,0 +1,17 @@ +import {defineConfig} from '@junobuild/config'; + +export default defineConfig({ + satellite: { + ids: { + development: '', + production: '' + }, + source: '' + }, + emulator: { + runner: { + type: '' + }, + : {} + } +}); diff --git a/templates/init/juno.runner.predeploy.config.js b/templates/init/juno.runner.predeploy.config.js new file mode 100644 index 00000000..6a73ffd0 --- /dev/null +++ b/templates/init/juno.runner.predeploy.config.js @@ -0,0 +1,19 @@ +import {defineConfig} from '@junobuild/config'; + +/** @type {import('@junobuild/config').JunoConfig} */ +export default defineConfig({ + satellite: { + ids: { + development: '', + production: '' + }, + source: '', + predeploy: [' build'] + }, + emulator: { + runner: { + type: '' + }, + : {} + } +}); diff --git a/templates/init/juno.runner.predeploy.config.ts b/templates/init/juno.runner.predeploy.config.ts new file mode 100644 index 00000000..5fe206bd --- /dev/null +++ b/templates/init/juno.runner.predeploy.config.ts @@ -0,0 +1,18 @@ +import {defineConfig} from '@junobuild/config'; + +export default defineConfig({ + satellite: { + ids: { + development: '', + production: '' + }, + source: '', + predeploy: [' build'] + }, + emulator: { + runner: { + type: '' + }, + : {} + } +}); diff --git a/tsconfig.json b/tsconfig.json index 158d981e..ce6df460 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,6 @@ "moduleResolution": "bundler", "outDir": "dist", "resolveJsonModule": true - } + }, + "exclude": ["templates"] } From e0fc798bbad74fcdf5dc6b31e9eccd2a98f479f0 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 2 Aug 2025 21:22:50 +0200 Subject: [PATCH 3/4] feat: check first for config --- src/services/dev/_runner.services.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/dev/_runner.services.ts b/src/services/dev/_runner.services.ts index 9a5c0f38..3cf4a892 100644 --- a/src/services/dev/_runner.services.ts +++ b/src/services/dev/_runner.services.ts @@ -30,6 +30,8 @@ import {createDeployTargetDir} from '../emulator/emulator.fs.services'; import {initConfigNoneInteractive} from '../init.services'; export const startContainer = async () => { + await assertAndInitConfig(); + const parsedResult = await readEmulatorConfig(); if (!parsedResult.success) { @@ -47,8 +49,6 @@ export const startContainer = async () => { await assertContainerRunnerRunning({runner: config.derivedConfig.runner}); - await assertAndInitConfig(); - await startEmulator({config}); }; From 4cc4e61cf69d20f4234cd848dfa7d786ccb327fc Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Sat, 2 Aug 2025 21:24:43 +0200 Subject: [PATCH 4/4] feat: use default --- src/services/dev/_runner.services.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/services/dev/_runner.services.ts b/src/services/dev/_runner.services.ts index 3cf4a892..33900fa5 100644 --- a/src/services/dev/_runner.services.ts +++ b/src/services/dev/_runner.services.ts @@ -19,7 +19,6 @@ import { type EmulatorType } from '../../types/emulator'; import {isHeadless} from '../../utils/process.utils'; -import {confirmAndExit} from '../../utils/prompt.utils'; import { assertContainerRunnerRunning, checkDockerVersion, @@ -127,13 +126,19 @@ const initConfigFile = async () => { const {runnerType} = await promptRunnerType(); + // Default skylab and docker, no need to specify those options in the config if they were picked. + const emulatorConfig = + emulatorType === 'skylab' && runnerType === 'docker' + ? undefined + : { + runner: { + type: runnerType + }, + ...(emulatorType === 'satellite' ? {satellite: {}} : {skylab: {}}) + }; + await initConfigNoneInteractive({ - emulatorConfig: { - runner: { - type: runnerType - }, - ...(emulatorType === 'satellite' ? {satellite: {}} : {skylab: {}}) - } + emulatorConfig }); };