From 33c54acaa36b22f60fa0edf07465a8ef45aca0d2 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Thu, 31 Jul 2025 13:03:09 +0200 Subject: [PATCH] feat: juno deploy --config --- src/commands/deploy.ts | 160 ++----------------------- src/help/deploy.help.ts | 3 +- src/services/config/config.services.ts | 2 +- src/services/deploy.services.ts | 155 ++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 154 deletions(-) create mode 100644 src/services/deploy.services.ts diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 8d04e8e4..efe9972c 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -1,27 +1,8 @@ -import {uploadAssetWithProposal} from '@junobuild/cdn'; -import { - deploy as cliDeploy, - deployWithProposal as cliDeployWithProposal, - type DeployResult, - type DeployResultWithProposal, - hasArgs, - type UploadFileWithProposal -} from '@junobuild/cli-tools'; -import {uploadBlob} from '@junobuild/core'; -import {yellow} from 'kleur'; -import {compare} from 'semver'; +import {hasArgs} from '@junobuild/cli-tools'; import {junoConfigExist} from '../configs/juno.config'; -import {clear} from '../services/assets/clear.services'; -import { - type DeployFnParams, - executeDeployImmediate, - executeDeployWithProposal, - type UploadFileFnParams, - type UploadFileFnParamsWithProposal -} from '../services/assets/deploy/deploy.execute.services'; -import {clearProposalStagedAssets} from '../services/changes/changes.clear.services'; +import {config} from '../services/config/config.services'; +import {deploy as deployServices} from '../services/deploy.services'; import {links} from '../services/links.services'; -import {getSatelliteVersion} from '../services/version.services'; import {init} from './init'; export const deploy = async (args?: string[]) => { @@ -29,138 +10,13 @@ export const deploy = async (args?: string[]) => { await init(); } - const clearOption = hasArgs({args, options: ['-c', '--clear']}); - const immediate = hasArgs({args, options: ['-i', '--immediate']}); + await deployServices(args); - if (immediate) { - await deployImmediate({clearOption}); - return; + const configOption = hasArgs({args, options: ['--config']}); + if (configOption) { + console.log(''); + await config(); } - // TODO: Remove this check once backward compatibility is no longer needed. - // Without falling back to `deploy --immediate`, we can't roll out GitHub Actions support - // without requiring developers to either upgrade their Satellites or add the `--immediate` flag in CI. - // To ease the release, we temporarily check the version. - const result = await getSatelliteVersion(); - - if (result.result === 'error') { - return; - } - - if (compare(result.version, '0.1.0') < 0) { - console.log( - `${yellow('[Warn]')} Your Satellite is outdated. Please upgrade to take full advantage of the new deployment flow.` - ); - await deployImmediate({clearOption}); - return; - } - - await deployWithProposal({args, clearOption}); -}; - -const deployWithProposal = async ({args, clearOption}: {args?: string[]; clearOption: boolean}) => { - const noCommit = hasArgs({args, options: ['--no-apply']}); - - const deployFn = async ({ - deploy, - satellite - }: DeployFnParams): Promise => - await cliDeployWithProposal({ - deploy: { - ...deploy, - includeAllFiles: clearOption - }, - proposal: { - clearAssets: clearOption, - autoCommit: !noCommit, - cdn: { - satellite - } - } - }); - - const uploadFileFn = async ({ - filename: storageFilename, - fullPath: storagePath, - data, - collection, - headers = [], - encoding, - satellite, - proposalId - }: UploadFileFnParamsWithProposal) => { - // Similar as in Juno Core SDK - // The IC certification does not currently support encoding - const filename = decodeURI(storageFilename); - const fullPath = storagePath ?? `/${collection}/${filename}`; - - await uploadAssetWithProposal({ - cdn: {satellite}, - proposalId, - asset: { - filename, - fullPath, - // @ts-expect-error type incompatibility NodeJS vs bundle - data, - collection, - headers, - encoding - } - }); - }; - - const result = await executeDeployWithProposal({ - deployFn, - uploadFileFn - }); - - if (result.result !== 'deployed') { - return; - } - - const {proposalId} = result; - - await clearProposalStagedAssets({ - args, - proposalId - }); - - await links(); -}; - -const deployImmediate = async ({clearOption}: {clearOption: boolean}) => { - if (clearOption) { - await clear(); - } - - const deployFn = async ({deploy}: DeployFnParams): Promise => - await cliDeploy(deploy); - - const uploadFileFn = async ({ - filename, - fullPath, - data, - collection, - headers, - encoding, - satellite - }: UploadFileFnParams) => { - await uploadBlob({ - satellite, - filename, - fullPath, - // @ts-expect-error type incompatibility NodeJS vs bundle - data, - collection, - headers, - encoding - }); - }; - - await executeDeployImmediate({ - deployFn, - uploadFileFn - }); - await links(); }; diff --git a/src/help/deploy.help.ts b/src/help/deploy.help.ts index c1cf367d..6fffd042 100644 --- a/src/help/deploy.help.ts +++ b/src/help/deploy.help.ts @@ -12,7 +12,8 @@ import {TITLE} from './help'; const usage = `Usage: ${green('juno')} ${cyan('deploy')} ${yellow('[options]')} Options: - ${yellow('-c, --clear')} Clear existing app files before proceeding with deployment. + ${yellow('--clear')} Clear existing app files before proceeding with deployment. + ${yellow('--config')} Apply configuration after deployment succeeds. ${yellow('--no-apply')} Submit the deployment as a change but do not apply it yet. ${OPTION_KEEP_STAGED} ${yellow('-i, --immediate')} Deploy files instantly (bypasses the change workflow). diff --git a/src/services/config/config.services.ts b/src/services/config/config.services.ts index 403d9aa6..ad8c2053 100644 --- a/src/services/config/config.services.ts +++ b/src/services/config/config.services.ts @@ -139,7 +139,7 @@ const getCurrentConfig = async ({ const loadCurrentConfig = async (params: { satellite: SatelliteParametersWithId; }): Promise => { - const spinner = ora('Loading...').start(); + const spinner = ora('Loading configuration...').start(); try { return await getCurrentConfig(params); diff --git a/src/services/deploy.services.ts b/src/services/deploy.services.ts new file mode 100644 index 00000000..668937c4 --- /dev/null +++ b/src/services/deploy.services.ts @@ -0,0 +1,155 @@ +import {uploadAssetWithProposal} from '@junobuild/cdn'; +import { + deploy as cliDeploy, + deployWithProposal as cliDeployWithProposal, + type DeployResult, + type DeployResultWithProposal, + hasArgs, + type UploadFileWithProposal +} from '@junobuild/cli-tools'; +import {uploadBlob} from '@junobuild/core'; +import {yellow} from 'kleur'; +import {compare} from 'semver'; +import {clear} from './assets/clear.services'; +import { + type DeployFnParams, + executeDeployImmediate, + executeDeployWithProposal, + type UploadFileFnParams, + type UploadFileFnParamsWithProposal +} from './assets/deploy/deploy.execute.services'; +import {clearProposalStagedAssets} from './changes/changes.clear.services'; +import {getSatelliteVersion} from './version.services'; + +export const deploy = async (args?: string[]) => { + const clearOption = hasArgs({args, options: ['--clear']}); + const immediate = hasArgs({args, options: ['-i', '--immediate']}); + + if (immediate) { + await deployImmediate({clearOption}); + return; + } + + // TODO: Remove this check once backward compatibility is no longer needed. + // Without falling back to `deploy --immediate`, we can't roll out GitHub Actions support + // without requiring developers to either upgrade their Satellites or add the `--immediate` flag in CI. + // To ease the release, we temporarily check the version. + const result = await getSatelliteVersion(); + + if (result.result === 'error') { + return; + } + + if (compare(result.version, '0.1.0') < 0) { + console.log( + `${yellow('[Warn]')} Your Satellite is outdated. Please upgrade to take full advantage of the new deployment flow.` + ); + await deployImmediate({clearOption}); + return; + } + + await deployWithProposal({args, clearOption}); +}; + +const deployWithProposal = async ({args, clearOption}: {args?: string[]; clearOption: boolean}) => { + const noCommit = hasArgs({args, options: ['--no-apply']}); + + const deployFn = async ({ + deploy, + satellite + }: DeployFnParams): Promise => + await cliDeployWithProposal({ + deploy: { + ...deploy, + includeAllFiles: clearOption + }, + proposal: { + clearAssets: clearOption, + autoCommit: !noCommit, + cdn: { + satellite + } + } + }); + + const uploadFileFn = async ({ + filename: storageFilename, + fullPath: storagePath, + data, + collection, + headers = [], + encoding, + satellite, + proposalId + }: UploadFileFnParamsWithProposal) => { + // Similar as in Juno Core SDK + // The IC certification does not currently support encoding + const filename = decodeURI(storageFilename); + const fullPath = storagePath ?? `/${collection}/${filename}`; + + await uploadAssetWithProposal({ + cdn: {satellite}, + proposalId, + asset: { + filename, + fullPath, + // @ts-expect-error type incompatibility NodeJS vs bundle + data, + collection, + headers, + encoding + } + }); + }; + + const result = await executeDeployWithProposal({ + deployFn, + uploadFileFn + }); + + if (result.result !== 'deployed') { + return; + } + + const {proposalId} = result; + + await clearProposalStagedAssets({ + args, + proposalId + }); +}; + +const deployImmediate = async ({clearOption}: {clearOption: boolean}) => { + if (clearOption) { + await clear(); + } + + const deployFn = async ({deploy}: DeployFnParams): Promise => + await cliDeploy(deploy); + + const uploadFileFn = async ({ + filename, + fullPath, + data, + collection, + headers, + encoding, + satellite + }: UploadFileFnParams) => { + await uploadBlob({ + satellite, + filename, + fullPath, + // @ts-expect-error type incompatibility NodeJS vs bundle + data, + collection, + headers, + encoding + }); + }; + + await executeDeployImmediate({ + deployFn, + uploadFileFn + }); +};