diff --git a/src/__tests__/app_export_cert.test.js b/src/__tests__/app_export_cert.test.js index 8a9841e..3c0790d 100644 --- a/src/__tests__/app_export_cert.test.js +++ b/src/__tests__/app_export_cert.test.js @@ -6,8 +6,8 @@ import path from 'path'; import exportAppToFile from '../lib/cmd/exportapp.js'; const options = { - // logLevel: process.env.CTRL_Q_LOG_LEVEL || 'info', - logLevel: process.env.CTRL_Q_LOG_LEVEL || 'verbose', + logLevel: process.env.CTRL_Q_LOG_LEVEL || 'info', + // logLevel: process.env.CTRL_Q_LOG_LEVEL || 'verbose', authType: process.env.CTRL_Q_AUTH_TYPE || 'cert', authCertFile: process.env.CTRL_Q_AUTH_CERT_FILE || './cert/client.pem', authCertKeyFile: process.env.CTRL_Q_AUTH_CERT_KEY_FILE || './cert/client_key.pem', @@ -63,150 +63,150 @@ describe('export apps to QVF files (cert auth)', () => { expect(files.length).toBeGreaterThan(0); // Delete output dir - // fs.rmSync(exportDir, { recursive: true }); + fs.rmSync(exportDir, { recursive: true }); }); - // /** - // * Two tags, overwrite - // * - // * --output-dir qvfs - // * --app-tag apiCreated 'Ctrl-Q import' - // * --exclude-app-data true - // * --qvf-name-format app-id app-name export-date export-time - // * --qvf-name-separator _ - // * --qvf-overwrite true - // */ - // test('export apps, two tags', async () => { - // options.outputDir = 'qvfs_tmp'; - // options.appTag = ['apiCreated', 'Ctrl-Q import']; - // options.excludeAppData = 'true'; - // options.qvfNameFormat = ['app-id', 'app-name', 'export-date', 'export-time']; - // options.qvfNameSeparator = '_'; - // options.qvfOverwrite = true; - - // const result = await exportAppToFile(options); - // expect(result).toBe(true); - - // // Verify that output folder contains at least one file - // const exportDir = path.resolve(options.outputDir); - // const files = fs.readdirSync(exportDir); - // expect(files.length).toBeGreaterThan(0); - - // // Delete output dir - // fs.rmSync(exportDir, { recursive: true }); - // }); - - // /** - // * Two tags, one ID, overwrite - // * - // * --output-dir qvfs - // * --app-tag apiCreated 'Ctrl-Q import' - // * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 - // * --exclude-app-data true - // * --qvf-name-format app-id app-name export-date export-time - // * --qvf-name-separator _ - // * --qvf-overwrite true - // */ - // test('export apps, two tags, one id', async () => { - // options.outputDir = 'qvfs_tmp'; - // options.appTag = ['apiCreated', 'Ctrl-Q import']; - // options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65']; - // options.excludeAppData = 'true'; - // options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; - // options.qvfNameSeparator = '_'; - // options.qvfOverwrite = true; - - // const result = await exportAppToFile(options); - // expect(result).toBe(true); - - // // Verify that output folder contains at least one file - // const exportDir = path.resolve(options.outputDir); - // const files = fs.readdirSync(exportDir); - // expect(files.length).toBeGreaterThan(0); - - // // Delete output dir - // fs.rmSync(exportDir, { recursive: true }); - // }); - - // /** - // * Two tags, two IDs, overwrite - // * - // * --output-dir qvfs - // * --app-tag apiCreated 'Ctrl-Q import' - // * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 - // * --exclude-app-data true - // * --qvf-name-format app-id app-name export-date export-time - // * --qvf-name-separator _ - // * --qvf-overwrite true - // */ - // test('export apps, two tags, two ids', async () => { - // options.outputDir = 'qvfs_tmp'; - // options.appTag = ['apiCreated', 'Ctrl-Q import']; - // options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65', '2933711d-6638-41d4-a2d2-6dd2d965208b']; - // options.excludeAppData = 'true'; - // options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; - // options.qvfNameSeparator = '_'; - // options.qvfOverwrite = true; - - // const result = await exportAppToFile(options); - // expect(result).toBe(true); - - // // Verify that output folder contains at least one file - // const exportDir = path.resolve(options.outputDir); - // const files = fs.readdirSync(exportDir); - // expect(files.length).toBeGreaterThan(0); - - // // Delete output dir - // fs.rmSync(exportDir, { recursive: true }); - // }); - - // /** - // * Two tags, two IDs, overwrite. Export metadata to Excel file - // * - // * --output-dir qvfs - // * --app-tag apiCreated 'Ctrl-Q import' - // * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 - // * --exclude-app-data true - // * --qvf-name-format app-id app-name export-date export-time - // * --qvf-name-separator _ - // * --qvf-overwrite true - // */ - // test('export apps, two tags, two ids, export metadata', async () => { - // options.outputDir = 'qvfs_tmp'; - // options.appTag = ['apiCreated', 'Ctrl-Q import']; - // options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65', '2933711d-6638-41d4-a2d2-6dd2d965208b']; - // options.excludeAppData = 'true'; - // options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; - // options.qvfNameSeparator = '_'; - // options.qvfOverwrite = true; - - // options.metadataFileCreate = true; - // options.metadataFileName = 'app-export.xlsx'; - // options.metadataFileFormat = 'excel'; - // options.metadataFileOverwrite = true; - - // const result = await exportAppToFile(options); - // expect(result).toBe(true); - - // // Verify that output folder contains at least one file - // const exportDir = path.resolve(options.outputDir); - // const files = fs.readdirSync(exportDir); - // expect(files.length).toBeGreaterThan(0); - - // // Verify that output Excel file has been created - // // Get all files in output folder - // const files2 = fs.readdirSync(exportDir); - - // // Filter out Excel files - // const excelFiles = files2.filter((file) => file.endsWith('.xlsx')); - // expect(excelFiles.length).toBe(1); - - // // Size of Exel file should be > 0 - // const excelFile = path.resolve(exportDir, excelFiles[0]); - // const stats = fs.statSync(excelFile); - // expect(stats.size).toBeGreaterThan(0); - - // // Delete output dir - // fs.rmSync(exportDir, { recursive: true }); - // }); + /** + * Two tags, overwrite + * + * --output-dir qvfs + * --app-tag apiCreated 'Ctrl-Q import' + * --exclude-app-data true + * --qvf-name-format app-id app-name export-date export-time + * --qvf-name-separator _ + * --qvf-overwrite true + */ + test('export apps, two tags', async () => { + options.outputDir = 'qvfs_tmp'; + options.appTag = ['apiCreated', 'Ctrl-Q import']; + options.excludeAppData = 'true'; + options.qvfNameFormat = ['app-id', 'app-name', 'export-date', 'export-time']; + options.qvfNameSeparator = '_'; + options.qvfOverwrite = true; + + const result = await exportAppToFile(options); + expect(result).toBe(true); + + // Verify that output folder contains at least one file + const exportDir = path.resolve(options.outputDir); + const files = fs.readdirSync(exportDir); + expect(files.length).toBeGreaterThan(0); + + // Delete output dir + fs.rmSync(exportDir, { recursive: true }); + }); + + /** + * Two tags, one ID, overwrite + * + * --output-dir qvfs + * --app-tag apiCreated 'Ctrl-Q import' + * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 + * --exclude-app-data true + * --qvf-name-format app-id app-name export-date export-time + * --qvf-name-separator _ + * --qvf-overwrite true + */ + test('export apps, two tags, one id', async () => { + options.outputDir = 'qvfs_tmp'; + options.appTag = ['apiCreated', 'Ctrl-Q import']; + options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65']; + options.excludeAppData = 'true'; + options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; + options.qvfNameSeparator = '_'; + options.qvfOverwrite = true; + + const result = await exportAppToFile(options); + expect(result).toBe(true); + + // Verify that output folder contains at least one file + const exportDir = path.resolve(options.outputDir); + const files = fs.readdirSync(exportDir); + expect(files.length).toBeGreaterThan(0); + + // Delete output dir + fs.rmSync(exportDir, { recursive: true }); + }); + + /** + * Two tags, two IDs, overwrite + * + * --output-dir qvfs + * --app-tag apiCreated 'Ctrl-Q import' + * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 + * --exclude-app-data true + * --qvf-name-format app-id app-name export-date export-time + * --qvf-name-separator _ + * --qvf-overwrite true + */ + test('export apps, two tags, two ids', async () => { + options.outputDir = 'qvfs_tmp'; + options.appTag = ['apiCreated', 'Ctrl-Q import']; + options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65', '2933711d-6638-41d4-a2d2-6dd2d965208b']; + options.excludeAppData = 'true'; + options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; + options.qvfNameSeparator = '_'; + options.qvfOverwrite = true; + + const result = await exportAppToFile(options); + expect(result).toBe(true); + + // Verify that output folder contains at least one file + const exportDir = path.resolve(options.outputDir); + const files = fs.readdirSync(exportDir); + expect(files.length).toBeGreaterThan(0); + + // Delete output dir + fs.rmSync(exportDir, { recursive: true }); + }); + + /** + * Two tags, two IDs, overwrite. Export metadata to Excel file + * + * --output-dir qvfs + * --app-tag apiCreated 'Ctrl-Q import' + * --app-id eb3ab049-d007-43d3-93da-5962f9208c65 + * --exclude-app-data true + * --qvf-name-format app-id app-name export-date export-time + * --qvf-name-separator _ + * --qvf-overwrite true + */ + test('export apps, two tags, two ids, export metadata', async () => { + options.outputDir = 'qvfs_tmp'; + options.appTag = ['apiCreated', 'Ctrl-Q import']; + options.appId = ['eb3ab049-d007-43d3-93da-5962f9208c65', '2933711d-6638-41d4-a2d2-6dd2d965208b']; + options.excludeAppData = 'true'; + options.qvfNameFormat = ['export-date', 'export-time', 'app-id', 'app-name']; + options.qvfNameSeparator = '_'; + options.qvfOverwrite = true; + + options.metadataFileCreate = true; + options.metadataFileName = 'app-export.xlsx'; + options.metadataFileFormat = 'excel'; + options.metadataFileOverwrite = true; + + const result = await exportAppToFile(options); + expect(result).toBe(true); + + // Verify that output folder contains at least one file + const exportDir = path.resolve(options.outputDir); + const files = fs.readdirSync(exportDir); + expect(files.length).toBeGreaterThan(0); + + // Verify that output Excel file has been created + // Get all files in output folder + const files2 = fs.readdirSync(exportDir); + + // Filter out Excel files + const excelFiles = files2.filter((file) => file.endsWith('.xlsx')); + expect(excelFiles.length).toBe(1); + + // Size of Exel file should be > 0 + const excelFile = path.resolve(exportDir, excelFiles[0]); + const stats = fs.statSync(excelFile); + expect(stats.size).toBeGreaterThan(0); + + // Delete output dir + fs.rmSync(exportDir, { recursive: true }); + }); }); diff --git a/src/globals.js b/src/globals.js index cfbdccf..072c975 100644 --- a/src/globals.js +++ b/src/globals.js @@ -74,24 +74,35 @@ export const setLoggingLevel = (newLevel) => { logTransports.find((transport) => transport.name === 'console').level = newLevel; }; -export const verifyFileExists = async (file) => { +export const verifyFileExists = async (file, silent = false) => { let exists = false; try { await Fs.stat(file); exists = true; } catch (err) { - if (isPkg) { - if (err.message) { - logger.error(`Error while checking if file ${file} exists: ${err.message}`); + if (!silent) { + if (isPkg) { + if (err.message) { + // Make message a bit nicer than what's returned from stat() + if (err.message.includes('no such file or directory')) { + logger.error(`File "${file}" does not exist.`); + } else { + logger.error(`Error while checking if file ${file} exists: ${err.message}`); + } + } else { + logger.error(`Error while checking if file ${file} exists: ${err}`); + } + } else if (err.message) { + if (err.message.includes('no such file or directory')) { + logger.error(`File "${file}" does not exist.`); + } else { + logger.error(`Error while checking if file ${file} exists: ${err.message}`); + } + } else if (err.stack) { + logger.error(`Error while checking if file ${file} exists: ${err.stack}`); } else { logger.error(`Error while checking if file ${file} exists: ${err}`); } - } else if (err.stack) { - logger.error(`Error while checking if file ${file} exists: ${err.stack}`); - } else if (err.message) { - logger.error(`Error while checking if file ${file} exists: ${err.message}`); - } else { - logger.error(`Error while checking if file ${file} exists: ${err}`); } } diff --git a/src/lib/app/class_allapps.js b/src/lib/app/class_allapps.js index 35f8c0d..a974968 100644 --- a/src/lib/app/class_allapps.js +++ b/src/lib/app/class_allapps.js @@ -1344,7 +1344,8 @@ class QlikSenseApps { logger.verbose(`Full path to QVF: ${fileName}`); // Check if destination QVF file already exists - const fileExists = await verifyFileExists(fileName); + // 2nd parameter controls whether to log info or not about file's existence + const fileExists = await verifyFileExists(fileName, true); let fileSkipped = false; let writer; diff --git a/src/lib/cmd/exportapp.js b/src/lib/cmd/exportapp.js index 79d64c3..dc18d7c 100644 --- a/src/lib/cmd/exportapp.js +++ b/src/lib/cmd/exportapp.js @@ -120,7 +120,8 @@ const exportAppToFile = async (options) => { logger.verbose(`Full path to app metadata file: ${fileName}`); // Check if app metadata file already exists - const fileExists = await verifyFileExists(fileName); + // 2nd parameter = true => don't output anything to log + const fileExists = await verifyFileExists(fileName, true); logger.info('------------------------------------');