Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 8 additions & 152 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,166 +1,22 @@
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[]) => {
if (!(await junoConfigExist())) {
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<UploadFileWithProposal>): Promise<DeployResultWithProposal> =>
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<DeployResult> =>
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();
};
3 changes: 2 additions & 1 deletion src/help/deploy.help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 1 addition & 1 deletion src/services/config/config.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const getCurrentConfig = async ({
const loadCurrentConfig = async (params: {
satellite: SatelliteParametersWithId;
}): Promise<CurrentConfig> => {
const spinner = ora('Loading...').start();
const spinner = ora('Loading configuration...').start();

try {
return await getCurrentConfig(params);
Expand Down
155 changes: 155 additions & 0 deletions src/services/deploy.services.ts
Original file line number Diff line number Diff line change
@@ -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<UploadFileWithProposal>): Promise<DeployResultWithProposal> =>
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<DeployResult> =>
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
});
};