Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ class AssetsPublishCommand extends Command {
assetsFlags.folderUid = assetsFlags['folder-uid'] || assetsFlags.folderUid;
assetsFlags.bulkPublish = assetsFlags['bulk-publish'] || assetsFlags.bulkPublish;
assetsFlags.apiVersion = assetsFlags['api-version'] || '3'; // setting default value for apiVersion
assetsFlags.dataDir = assetsFlags['data-dir'] || assetsFlags.dataDir;
assetsFlags.backupDir = assetsFlags['backup-dir'] || assetsFlags.backupDir;
delete assetsFlags['api-version'];
delete assetsFlags['retry-failed'];
delete assetsFlags['folder-uid'];
delete assetsFlags['bulk-publish'];
delete assetsFlags['data-dir'];
delete assetsFlags['backup-dir'];

let updatedFlags;
try {
Expand Down Expand Up @@ -113,15 +113,15 @@ class AssetsPublishCommand extends Command {
}
}

validate({ environments, retryFailed, locales, dataDir, 'source-env': sourceEnv, 'delivery-token': deliveryToken }) {
validate({ environments, retryFailed, locales, backupDir, 'source-env': sourceEnv, 'delivery-token': deliveryToken }) {
let missing = [];
if (retryFailed) {
return true;
}

// In data-dir mode, environments and locales are derived per-asset from the
// In backup-dir mode, environments and locales are derived per-asset from the
// backup publish_details, so they are not required on the command line.
if (dataDir) {
if (backupDir) {
return true;
}

Expand Down Expand Up @@ -189,10 +189,10 @@ AssetsPublishCommand.flags = {
'(optional) The UID of the Assets’ folder from which the assets need to be published. The default value is cs_root.',
exclusive: ['source-env'],
}),
'data-dir': flags.string({
'backup-dir': flags.string({
description:
'(optional) Path to the import backup directory. When set, each imported asset is published only to the environments and locales it was published to in the source stack (read from the backup’s publish details and asset UID mapping), with asset-scan gating applied. Intended for the post-import publish flow.',
exclusive: ['source-env', 'folder-uid'],
exclusive: ['source-env', 'folder-uid', 'environments', 'locales'],
}),
'bulk-publish': flags.string({
description: 'Set this flag to use Contentstack’s Bulk Publish APIs. It is true, by default.',
Expand Down Expand Up @@ -273,13 +273,13 @@ AssetsPublishCommand.examples = [
'Using --stack-api-key flag',
'csdx cm:assets:publish --environments [ENVIRONMENT 1] [ENVIRONMENT 2] --locales [LOCALE] --stack-api-key [STACK API KEY]',
'',
'Using --data-dir flag (publish imported assets to their original environments after asset scanning)',
'csdx cm:assets:publish --data-dir [PATH TO IMPORT BACKUP DIR] --stack-api-key [STACK API KEY]',
'Using --backup-dir flag (publish imported assets to their original environments after asset scanning)',
'csdx cm:assets:publish --backup-dir [PATH TO IMPORT BACKUP DIR] --stack-api-key [STACK API KEY]',
];

AssetsPublishCommand.aliases = ['cm:bulk-publish:assets'];

AssetsPublishCommand.usage =
'cm:assets:publish [-a <value>] [--retry-failed <value>] [-e <value>] [--folder-uid <value>] [--data-dir <value>] [--bulk-publish <value>] [-c <value>] [-y] [--locales <value>] [--branch <value>] [--delivery-token <value>] [--source-env <value>]';
'cm:assets:publish [-a <value>] [--retry-failed <value>] [-e <value>] [--folder-uid <value>] [--backup-dir <value>] [--bulk-publish <value>] [-c <value>] [-y] [--locales <value>] [--branch <value>] [--delivery-token <value>] [--source-env <value>]';

module.exports = AssetsPublishCommand;
4 changes: 2 additions & 2 deletions packages/contentstack-bulk-publish/src/consumer/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ function displayEntriesDetails(sanitizedData, action, mapping = []) {
function displayAssetsDetails(sanitizedData, action, mapping) {
if (action === 'bulk_publish') {
sanitizedData.forEach((asset) => {
asset?.publish_details.forEach((pd) => {
asset?.publish_details?.forEach((pd) => {
if (Object.keys(mapping).includes(pd.environment)) {
console.log(
chalk.green(
`Asset UID: '${asset.uid}'${pd.version ? `, Version: '${pd.version}'` : ''}${
asset.locale ? `, Locale: '${asset.locale}'` : ''
asset.locale ? `, Locale: '${asset.locale}'` : ''}
}, Environment: ${pd.environment}`,
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,16 +256,16 @@ async function processPendingAssets(pendingItems, stack, bulkPublish, environmen
* subset). The single in-memory floor is the asset uid-mapping file itself (same
* as import's publish()); for very large stacks raise Node's --max-old-space-size.
*/
async function getAssetsFromBackup(stack, dataDir, bulkPublish, apiVersion, bulkPublishLimit) {
const assetsPath = path.join(dataDir, 'assets');
async function getAssetsFromBackup(stack, backupDir, bulkPublish, apiVersion, bulkPublishLimit) {
const assetsPath = path.join(backupDir, 'assets');
const assetsIndexPath = path.join(assetsPath, 'assets.json');
const assetUidMapperPath = path.join(dataDir, 'mapper', 'assets', 'uid-mapping.json');
const envUidMapperPath = path.join(dataDir, 'mapper', 'environments', 'uid-mapping.json');
const environmentsPath = path.join(dataDir, 'environments', 'environments.json');
const assetUidMapperPath = path.join(backupDir, 'mapper', 'assets', 'uid-mapping.json');
const envUidMapperPath = path.join(backupDir, 'mapper', 'environments', 'uid-mapping.json');
const environmentsPath = path.join(backupDir, 'environments', 'environments.json');

// A backup with no assets is a legitimate outcome of a successful import that
// had 0 assets (assets.json is never produced) — exit cleanly, not as a crash.
// A genuinely wrong --data-dir surfaces via the uid-mapping/environments guards below.
// A genuinely wrong --backup-dir surfaces via the uid-mapping/environments guards below.
if (!existsSync(assetsPath) || !existsSync(assetsIndexPath)) {
console.log(chalk.yellow('No assets found in backup — nothing to publish.'));
return;
Expand Down Expand Up @@ -457,7 +457,7 @@ function setConfig(conf, bp) {
scanSummary = { clean: 0, quarantined: 0, inQueue: 0, noStatus: 0 };
}

async function start({ retryFailed, bulkPublish, environments, folderUid, locales, apiVersion, dataDir }, stack, config) {
async function start({ retryFailed, bulkPublish, environments, folderUid, locales, apiVersion, backupDir }, stack, config) {
process.on('beforeExit', async () => {
// Print the scan summary here (not inline after enqueueing):
printScanSummary(scanSummary);
Expand Down Expand Up @@ -498,12 +498,12 @@ async function start({ retryFailed, bulkPublish, environments, folderUid, locale
} else {
await retryFailedLogs(retryFailed, { assetQueue: queue }, 'publish');
}
} else if (dataDir) {
} else if (backupDir) {
// Post-import flow: publish each imported asset only to its original
// environments/locales (from backup publish_details), scan-gated.
setConfig(config, bulkPublish);
const bulkPublishLimit = fetchBulkPublishLimit(stack?.org_uid);
await getAssetsFromBackup(stack, dataDir, bulkPublish, apiVersion, bulkPublishLimit);
await getAssetsFromBackup(stack, backupDir, bulkPublish, apiVersion, bulkPublishLimit);
} else if (folderUid) {
setConfig(config, bulkPublish);
const bulkPublishLimit = fetchBulkPublishLimit(stack?.org_uid);
Expand Down
17 changes: 17 additions & 0 deletions packages/contentstack-import/src/commands/cm/stacks/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,23 @@ export default class ImportCommand extends Command {

log.success(`The log has been stored at: ${getLogPath()}`, importConfig.context);
log.info(`The backup content has been stored at: ${backupDir}`, importConfig.context);

// Closing reminder: when assets were imported but not published inline
// (asset scanning enabled, or --skip-assets-publish), point the user to
// cm:assets:publish with the backup dir and stack pre-filled so the note
// isn't lost in the per-module logs above.
const assetsImported = importConfig.moduleName
? importConfig.moduleName === 'assets'
: importConfig.modules?.types?.includes('assets');
// Mirror the publish gate in assets.ts (`!skipAssetsPublish`): assets are
// left unpublished exactly when skipAssetsPublish is set — which also
// covers the scanning case, since detecting scanning sets skipAssetsPublish.
if (!result?.noSuccessMsg && assetsImported && importConfig.skipAssetsPublish) {
log.info(
`Note: assets were imported but not published asset scanning is enabled and must complete first. To publish them, run:\n csdx cm:assets:publish --backup-dir ${backupDir} --stack-api-key ${importConfig.apiKey}`,
importConfig.context,
);
}
} catch (error) {
handleAndLogError(error);
log.info(`The log has been stored at '${getLogPath()}'`);
Expand Down
Loading