Diff
checker
文本
文本
图像
文档
Excel
文件夹
Legal
Enterprise
桌面版
定价
登录
下载 Diffchecker 桌面版
比较文本
查找两个文本文件之间的差异
工具
历史
实时编辑器
折叠未更改行
关闭换行
视图
拆分
统一
比对精度
智能
单词
字符
语法高亮
选择语法
忽略
文本转换
转到第一个差异
编辑输入
Diffchecker Desktop
运行Diffchecker最安全的方式。获取Diffchecker桌面应用:您的差异永远不会离开您的电脑!
获取桌面版
resultify-hubspot-cms-windows
创建于
2年前
差异永不过期
清除
导出
分享
解释
60 删除
行
总计
删除
字符
总计
删除
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
424 行
全部复制
38 添加
行
总计
添加
字符
总计
添加
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
412 行
全部复制
/** @module hubspot/upload */
/** @module hubspot/upload */
/// <reference path="../types/types.js" />
/// <reference path="../types/types.js" />
import fsPromises from 'fs/promises'
import fsPromises from 'fs/promises'
import uploadFolder from '@hubspot/local-dev-lib/cms/uploadFolder'
import uploadFolder from '@hubspot/local-dev-lib/cms/uploadFolder'
import { deleteFile, getDirectoryContentsByPath } from '@hubspot/local-dev-lib/api/fileMapper'
import { deleteFile, getDirectoryContentsByPath } from '@hubspot/local-dev-lib/api/fileMapper'
import { setLogLevel, LOG_LEVEL } from '@hubspot/local-dev-lib/logger'
import { setLogLevel, LOG_LEVEL } from '@hubspot/local-dev-lib/logger'
import { isAllowedExtension } from '@hubspot/local-dev-lib/path'
import { isAllowedExtension } from '@hubspot/local-dev-lib/path'
import { createIgnoreFilter } from '@hubspot/local-dev-lib/ignoreRules'
import { createIgnoreFilter } from '@hubspot/local-dev-lib/ignoreRules'
import { walk } from '@hubspot/local-dev-lib/fs'
import { walk } from '@hubspot/local-dev-lib/fs'
import * as ui from '../utils/ui.js'
import * as ui from '../utils/ui.js'
import { getThemeOptions } from '../utils/options.js'
import { getThemeOptions } from '../utils/options.js'
import { throwErrorIfMissingScope } from './auth/scopes.js'
import { throwErrorIfMissingScope } from './auth/scopes.js'
import ora from 'ora'
import ora from 'ora'
import chalk from 'chalk'
import chalk from 'chalk'
import checkbox from '@inquirer/checkbox'
import checkbox from '@inquirer/checkbox'
import confirm from '@inquirer/confirm'
import confirm from '@inquirer/confirm'
import { getFileList, isFileDir } from '../utils/fs.js'
import { getFileList, isFileDir } from '../utils/fs.js'
复制
已复制
复制
已复制
import path from 'path'
/**
/**
* @type {"draft" | "publish"}
* @type {"draft" | "publish"}
*/
*/
let cmsMode = 'publish'
let cmsMode = 'publish'
if (process.env.HUB_MODE === 'draft') {
if (process.env.HUB_MODE === 'draft') {
cmsMode = 'draft'
cmsMode = 'draft'
}
}
/**
/**
* #### Walks the src folder for files, filters them based on ignore filter.
* #### Walks the src folder for files, filters them based on ignore filter.
* @async
* @async
* @private
* @private
* @param {string} src - src folder
* @param {string} src - src folder
* @returns {Promise<Array<string>>} src file list
* @returns {Promise<Array<string>>} src file list
*/
*/
const getUploadableFileList = async (src) => {
const getUploadableFileList = async (src) => {
/**
/**
* @type {Array<string>}
* @type {Array<string>}
*/
*/
let filePaths = []
let filePaths = []
try {
try {
filePaths = await walk(src)
filePaths = await walk(src)
} catch (error) {
} catch (error) {
console.error(error)
console.error(error)
}
}
const allowedFiles = filePaths.filter((/** @type {any} */ file) => {
const allowedFiles = filePaths.filter((/** @type {any} */ file) => {
if (!isAllowedExtension(file)) {
if (!isAllowedExtension(file)) {
return false
return false
}
}
return true
return true
// @ts-ignore
// @ts-ignore
}).filter(createIgnoreFilter())
}).filter(createIgnoreFilter())
return allowedFiles
return allowedFiles
}
}
/**
/**
* #### Reads the .cihsignore file and returns the list of files to ignore.
* #### Reads the .cihsignore file and returns the list of files to ignore.
* @private
* @private
* @async
* @async
* @returns {Promise<string[]>} List of files to ignore.
* @returns {Promise<string[]>} List of files to ignore.
*/
*/
复制
已复制
复制
已复制
async function readCihsIgnore
() {
async function readCihsIgnore
() {
return new Promise((resolve) =>
{
try
{
const cihsignorePath = path.join(
process.cwd()
, '
.cihsignore
');
if (await isFileDir(`${
process.cwd()
}/
.cihsignore
`)) {
const ignoreContent = await
fsPromises.readFile(
`${process.cwd()}/.
cihsignore
`
, 'utf8'
)
fsPromises.access(cihsignorePath)
return
ignoreContent
.split(
'\n')
.map(line => line.trim())
.filter(line => line && !line.startsWith('#'))
.then(() =>
fsPromises.readFile(
cihsignore
Path
, 'utf8'
)
)
} else {
.then(ignoreContent => {
return []
const ignoredPaths =
ignoreContent
}
.split(
/\r?\n/)
}
catch
(error
)
{
.map(line => line.trim())
console.error('Error reading .cihsignore file:', error)
.filter(line => line && !line.startsWith('#'))
;
return []
resolve(ignoredPaths);
}
})
.
catch
(error
=>
{
console.error('Error reading .cihsignore file:', error)
;
resolve([]);
});
}
);
}
}
/**
/**
* #### Walks the src folder for files, filters them based on ignore filter and CI .cihsignore file.
* #### Walks the src folder for files, filters them based on ignore filter and CI .cihsignore file.
* @async
* @async
* @private
* @private
* @param {string} src - src folder
* @param {string} src - src folder
* @returns {Promise<Array<string>>} src file list
* @returns {Promise<Array<string>>} src file list
*/
*/
const getCiUploadableFileList = async (src) => {
const getCiUploadableFileList = async (src) => {
/**
/**
* @type {Array<string>}
* @type {Array<string>}
*/
*/
let filePaths = []
let filePaths = []
try {
try {
filePaths = await walk(src)
filePaths = await walk(src)
} catch (error) {
} catch (error) {
console.error(error)
console.error(error)
}
}
let allowedFiles = filePaths.filter((/** @type {any} */ file) => {
let allowedFiles = filePaths.filter((/** @type {any} */ file) => {
if (!isAllowedExtension(file)) {
if (!isAllowedExtension(file)) {
return false
return false
}
}
return true
return true
// @ts-ignore
// @ts-ignore
}).filter(createIgnoreFilter())
}).filter(createIgnoreFilter())
async function filterFiles (/** @type {any} */ files) {
async function filterFiles (/** @type {any} */ files) {
const ignoredPaths = await readCihsIgnore()
const ignoredPaths = await readCihsIgnore()
return files.filter((/** @type {any} */ file) => !ignoredPaths.some(ignoredPath => file.includes(ignoredPath)))
return files.filter((/** @type {any} */ file) => !ignoredPaths.some(ignoredPath => file.includes(ignoredPath)))
}
}
allowedFiles = await filterFiles(allowedFiles)
allowedFiles = await filterFiles(allowedFiles)
return allowedFiles
return allowedFiles
}
}
/**
/**
* #### upload all HubSpot theme files
* #### upload all HubSpot theme files
* @async
* @async
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {string} themeName - theme name
* @param {string} themeName - theme name
* @returns undefined
* @returns undefined
*/
*/
async function uploadTheme (config, themeName) {
async function uploadTheme (config, themeName) {
try {
try {
const timeStart = ui.startTask('uploadTheme')
const timeStart = ui.startTask('uploadTheme')
const cmslibOptions = getThemeOptions()
const cmslibOptions = getThemeOptions()
复制
已复制
复制
已复制
const src =
path.join(
process.cwd()
,
cmslibOptions.themeFolder
)
const src =
`${
process.cwd()
}/${
cmslibOptions.themeFolder
}`
const dest = themeName
const dest = themeName
const portalId = config.portals[0].portalId
const portalId = config.portals[0].portalId
throwErrorIfMissingScope(config, 'design_manager')
throwErrorIfMissingScope(config, 'design_manager')
setLogLevel(LOG_LEVEL.LOG)
setLogLevel(LOG_LEVEL.LOG)
const uploadableFileList = await getUploadableFileList(src)
const uploadableFileList = await getUploadableFileList(src)
await uploadFolder.uploadFolder(
await uploadFolder.uploadFolder(
portalId,
portalId,
src,
src,
dest,
dest,
{ overwrite: false },
{ overwrite: false },
{ saveOutput: true, convertFields: false },
{ saveOutput: true, convertFields: false },
uploadableFileList,
uploadableFileList,
cmsMode
cmsMode
)
)
ui.endTask({ taskName: 'uploadTheme', timeStart })
ui.endTask({ taskName: 'uploadTheme', timeStart })
} catch (error) {
} catch (error) {
console.error(chalk.red('Error:'))
console.error(chalk.red('Error:'))
console.error(error.message)
console.error(error.message)
process.exitCode = 1
process.exitCode = 1
if (process.env.DEBUG_MODE === 'debug') {
if (process.env.DEBUG_MODE === 'debug') {
console.error(error)
console.error(error)
process.exitCode = 1
process.exitCode = 1
}
}
}
}
}
}
/**
/**
* #### delete all templates in theme and reupload them
* #### delete all templates in theme and reupload them
* @async
* @async
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {string} themeName - theme name
* @param {string} themeName - theme name
* @returns undefined
* @returns undefined
*/
*/
async function cleanUploadThemeTemplates (config, themeName) {
async function cleanUploadThemeTemplates (config, themeName) {
const timeStart = ui.startTask('cleanUploadThemeTemplates')
const timeStart = ui.startTask('cleanUploadThemeTemplates')
const spinner = ora('Reupload all templates').start()
const spinner = ora('Reupload all templates').start()
try {
try {
const cmslibOptions = getThemeOptions()
const cmslibOptions = getThemeOptions()
复制
已复制
复制
已复制
const src =
path.join(
process.cwd()
,
cmslibOptions.themeFolder
, '
templates
')
const src =
`${
process.cwd()
}/${
cmslibOptions.themeFolder
}/
templates
`
const dest =
path.join(
themeName
, '
templates
')
const dest =
`${
themeName
}/
templates
`
const portalId = config.portals[0].portalId
const portalId = config.portals[0].portalId
throwErrorIfMissingScope(config, 'design_manager')
throwErrorIfMissingScope(config, 'design_manager')
setLogLevel(LOG_LEVEL.NONE)
setLogLevel(LOG_LEVEL.NONE)
const uploadableFileList = await getUploadableFileList(src)
const uploadableFileList = await getUploadableFileList(src)
const filesToDelete = await getDirectoryContentsByPath(portalId, dest)
const filesToDelete = await getDirectoryContentsByPath(portalId, dest)
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
for await (const file of filesToDelete.data.children) {
for await (const file of filesToDelete.data.children) {
// @ts-ignore
// @ts-ignore
if (file.includes('.html')) {
if (file.includes('.html')) {
复制
已复制
复制
已复制
await deleteFile(portalId,
path.join(
dest
,
file
)
)
await deleteFile(portalId,
`${
dest
}/${
file
}`
)
}
}
}
}
}
}
await uploadFolder.uploadFolder(
await uploadFolder.uploadFolder(
portalId,
portalId,
src,
src,
dest,
dest,
{ overwrite: false },
{ overwrite: false },
{ saveOutput: true, convertFields: false },
{ saveOutput: true, convertFields: false },
uploadableFileList,
uploadableFileList,
cmsMode
cmsMode
)
)
spinner.succeed()
spinner.succeed()
ui.endTask({ taskName: 'cleanUploadThemeTemplates', timeStart })
ui.endTask({ taskName: 'cleanUploadThemeTemplates', timeStart })
} catch (error) {
} catch (error) {
spinner.fail()
spinner.fail()
console.error(chalk.red('Error:'))
console.error(chalk.red('Error:'))
console.error(error.message)
console.error(error.message)
process.exitCode = 1
process.exitCode = 1
if (process.env.DEBUG_MODE === 'debug') {
if (process.env.DEBUG_MODE === 'debug') {
console.error(error)
console.error(error)
process.exitCode = 1
process.exitCode = 1
}
}
}
}
}
}
/**
/**
* #### clean theme and reupload it
* #### clean theme and reupload it
* @async
* @async
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {string} themeName - theme name
* @param {string} themeName - theme name
* @returns undefined
* @returns undefined
*/
*/
async function cleanUploadTheme (config, themeName) {
async function cleanUploadTheme (config, themeName) {
const timeStart = ui.startTask('cleanUploadTheme')
const timeStart = ui.startTask('cleanUploadTheme')
const dest = themeName
const dest = themeName
const spinner = ora(`Clean ${dest} folder before upload`)
const spinner = ora(`Clean ${dest} folder before upload`)
try {
try {
const cmslibOptions = getThemeOptions()
const cmslibOptions = getThemeOptions()
复制
已复制
复制
已复制
const src =
path.join(
process.cwd()
,
cmslibOptions.themeFolder
)
const src =
`${
process.cwd()
}/${
cmslibOptions.themeFolder
}`
const portalId = config.portals[0].portalId
const portalId = config.portals[0].portalId
throwErrorIfMissingScope(config, 'design_manager')
throwErrorIfMissingScope(config, 'design_manager')
setLogLevel(LOG_LEVEL.LOG)
setLogLevel(LOG_LEVEL.LOG)
const uploadableFileList = await getUploadableFileList(src)
const uploadableFileList = await getUploadableFileList(src)
spinner.start()
spinner.start()
const filesToDelete = await getDirectoryContentsByPath(portalId, '/')
const filesToDelete = await getDirectoryContentsByPath(portalId, '/')
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
for await (const file of filesToDelete.data.children) {
for await (const file of filesToDelete.data.children) {
// @ts-ignore
// @ts-ignore
if (file === dest) {
if (file === dest) {
await deleteFile(portalId, file)
await deleteFile(portalId, file)
}
}
}
}
}
}
spinner.succeed()
spinner.succeed()
await uploadFolder.uploadFolder(
await uploadFolder.uploadFolder(
portalId,
portalId,
src,
src,
dest,
dest,
{ overwrite: false },
{ overwrite: false },
{ saveOutput: true, convertFields: false },
{ saveOutput: true, convertFields: false },
uploadableFileList,
uploadableFileList,
cmsMode
cmsMode
)
)
ui.endTask({ taskName: 'cleanUploadTheme', timeStart })
ui.endTask({ taskName: 'cleanUploadTheme', timeStart })
} catch (error) {
} catch (error) {
spinner.fail()
spinner.fail()
console.error(chalk.red('Error:'))
console.error(chalk.red('Error:'))
console.error(error.message)
console.error(error.message)
process.exitCode = 1
process.exitCode = 1
if (process.env.DEBUG_MODE === 'debug') {
if (process.env.DEBUG_MODE === 'debug') {
console.error(error)
console.error(error)
process.exitCode = 1
process.exitCode = 1
}
}
}
}
}
}
/**
/**
* #### CI clean theme upload
* #### CI clean theme upload
* @async
* @async
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {string} themeName - theme name
* @param {string} themeName - theme name
* @returns undefined
* @returns undefined
*/
*/
async function ciUploadTheme (config, themeName) {
async function ciUploadTheme (config, themeName) {
const timeStart = ui.startTask('ciUpload')
const timeStart = ui.startTask('ciUpload')
const dest = themeName
const dest = themeName
const spinner = ora(`Clean ${dest} folder before upload`)
const spinner = ora(`Clean ${dest} folder before upload`)
try {
try {
const cmslibOptions = getThemeOptions()
const cmslibOptions = getThemeOptions()
复制
已复制
复制
已复制
const src =
path.join(
process.cwd()
,
cmslibOptions.themeFolder
)
const src =
`${
process.cwd()
}/${
cmslibOptions.themeFolder
}`
const portalId = config.portals[0].portalId
const portalId = config.portals[0].portalId
throwErrorIfMissingScope(config, 'design_manager')
throwErrorIfMissingScope(config, 'design_manager')
setLogLevel(LOG_LEVEL.LOG)
setLogLevel(LOG_LEVEL.LOG)
const uploadableFileList = await getCiUploadableFileList(src)
const uploadableFileList = await getCiUploadableFileList(src)
spinner.start()
spinner.start()
const filesToDelete = await getDirectoryContentsByPath(portalId, '/')
const filesToDelete = await getDirectoryContentsByPath(portalId, '/')
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) {
for await (const file of filesToDelete.data.children) {
for await (const file of filesToDelete.data.children) {
// @ts-ignore
// @ts-ignore
if (file === dest) {
if (file === dest) {
await deleteFile(portalId, file)
await deleteFile(portalId, file)
}
}
}
}
}
}
spinner.succeed()
spinner.succeed()
await uploadFolder.uploadFolder(
await uploadFolder.uploadFolder(
portalId,
portalId,
src,
src,
dest,
dest,
{ overwrite: false },
{ overwrite: false },
{ saveOutput: true, convertFields: false },
{ saveOutput: true, convertFields: false },
uploadableFileList,
uploadableFileList,
cmsMode
cmsMode
)
)
ui.endTask({ taskName: 'ciUpload', timeStart })
ui.endTask({ taskName: 'ciUpload', timeStart })
} catch (error) {
} catch (error) {
spinner.fail()
spinner.fail()
console.error(chalk.red('Error:'))
console.error(chalk.red('Error:'))
console.error(error.message)
console.error(error.message)
process.exitCode = 1
process.exitCode = 1
if (process.env.DEBUG_MODE === 'debug') {
if (process.env.DEBUG_MODE === 'debug') {
console.error(error)
console.error(error)
process.exitCode = 1
process.exitCode = 1
}
}
}
}
}
}
/**
/**
* #### prepare file choices for prompt
* #### prepare file choices for prompt
* @private
* @private
* @param {Array<FILE_LIST>} files - hubdb files
* @param {Array<FILE_LIST>} files - hubdb files
* @returns {Array<{name:string, value:{path:string, name:string, label:string}}>} files choices
* @returns {Array<{name:string, value:{path:string, name:string, label:string}}>} files choices
*/
*/
function prepareFileChoices (files) {
function prepareFileChoices (files) {
const fileChoices = []
const fileChoices = []
for (const file of files) {
for (const file of files) {
fileChoices.push({ name: file.name, value: { path: file.path, name: file.name, label: file.name.slice(0, -7) } })
fileChoices.push({ name: file.name, value: { path: file.path, name: file.name, label: file.name.slice(0, -7) } })
}
}
return fileChoices
return fileChoices
}
}
/**
/**
* #### select standalome modules to upload
* #### select standalome modules to upload
* @async
* @async
* @private
* @private
* @param {Array<FILE_LIST>} dirs - files
* @param {Array<FILE_LIST>} dirs - files
* @returns {Promise<Array<{path:string, name:string, label:string}>>} selected files
* @returns {Promise<Array<{path:string, name:string, label:string}>>} selected files
*/
*/
async function selectModules (dirs) {
async function selectModules (dirs) {
const selectFiles = {
const selectFiles = {
message: 'Pick modules:',
message: 'Pick modules:',
choices: prepareFileChoices(dirs),
choices: prepareFileChoices(dirs),
pageSize: 5,
pageSize: 5,
loop: false
loop: false
}
}
const confirmPortal = (/** @type {any} */ selectedFiles) => {
const confirmPortal = (/** @type {any} */ selectedFiles) => {
const filesNameList = []
const filesNameList = []
for (const file of selectedFiles) {
for (const file of selectedFiles) {
filesNameList.push(file.name)
filesNameList.push(file.name)
}
}
if (filesNameList.length === 1) {
if (filesNameList.length === 1) {
return {
return {
message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} module?`
message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} module?`
}
}
} else {
} else {
return {
return {
message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} modules?`
message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} modules?`
}
}
}
}
}
}
// select files
// select files
let selectedTables = await checkbox(selectFiles)
let selectedTables = await checkbox(selectFiles)
if (!selectedTables.length) {
if (!selectedTables.length) {
console.log(chalk.yellow('No modules selected'))
console.log(chalk.yellow('No modules selected'))
process.exit(0)
process.exit(0)
}
}
// confirm selection
// confirm selection
let confirmed = await confirm(confirmPortal(selectedTables))
let confirmed = await confirm(confirmPortal(selectedTables))
if (!confirmed) {
if (!confirmed) {
// try again one more time
// try again one more time
selectedTables = await checkbox(selectFiles)
selectedTables = await checkbox(selectFiles)
if (!selectedTables.length) {
if (!selectedTables.length) {
console.log(chalk.yellow('No modules selected'))
console.log(chalk.yellow('No modules selected'))
process.exit(0)
process.exit(0)
}
}
confirmed = await confirm(confirmPortal(selectedTables))
confirmed = await confirm(confirmPortal(selectedTables))
if (!confirmed) {
if (!confirmed) {
process.exit(0)
process.exit(0)
}
}
}
}
return selectedTables
return selectedTables
}
}
/**
/**
* #### upload module to HubSpot
* #### upload module to HubSpot
* @async
* @async
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config
* @returns undefined
* @returns undefined
*/
*/
async function uploadSelectedModules (config) {
async function uploadSelectedModules (config) {
try {
try {
const timeStart = ui.startTask('uploadModules')
const timeStart = ui.startTask('uploadModules')
复制
已复制
复制
已复制
const modulesToUpload = await getFileList(
path.normalize(
'standalone-modules/*.module'
)
, {
const modulesToUpload = await getFileList(
'standalone-modules/*.module'
, {
objectMode: true,
onlyDirectories: true,
deep: 1
})
objectMode: true,
onlyDirectories: true,
deep: 1
})
const selectedModules = await selectModules(modulesToUpload)
const selectedModules = await selectModules(modulesToUpload)
const portalId = config.portals[0].portalId
const portalId = config.portals[0].portalId
throwErrorIfMissingScope(config, 'design_manager')
throwErrorIfMissingScope(config, 'design_manager')
setLogLevel(LOG_LEVEL.LOG)
setLogLevel(LOG_LEVEL.LOG)
for (const module of selectedModules) {
for (const module of selectedModules) {
const src = module.path
const src = module.path
const dest = module.name
const dest = module.name
if (await isFileDir(src) === false) {
if (await isFileDir(src) === false) {
throw new Error(`${chalk.red('Error')}: Module ${chalk.green(src)} does not exist`)
throw new Error(`${chalk.red('Error')}: Module ${chalk.green(src)} does not exist`)
}
}
const uploadableFileList = await getUploadableFileList(src)
const uploadableFileList = await getUploadableFileList(src)
await uploadFolder.uploadFolder(
await uploadFolder.uploadFolder(
portalId,
portalId,
src,
src,
dest,
dest,
{ overwrite: false },
{ overwrite: false },
{ saveOutput: true, convertFields: false },
{ saveOutput: true, convertFields: false },
uploadableFileList,
uploadableFileList,
cmsMode
cmsMode
)
)
}
}
ui.endTask({ taskName: 'uploadModules', timeStart })
ui.endTask({ taskName: 'uploadModules', timeStart })
} catch (error) {
} catch (error) {
console.error(chalk.red('Error:'))
console.error(chalk.red('Error:'))
console.error(error.message)
console.error(error.message)
process.exitCode = 1
process.exitCode = 1
if (process.env.DEBUG_MODE === 'debug') {
if (process.env.DEBUG_MODE === 'debug') {
console.error(error)
console.error(error)
process.exitCode = 1
process.exitCode = 1
}
}
}
}
}
}
export { uploadTheme, cleanUploadThemeTemplates, cleanUploadTheme, ciUploadTheme, uploadSelectedModules }
export { uploadTheme, cleanUploadThemeTemplates, cleanUploadTheme, ciUploadTheme, uploadSelectedModules }
复制
已复制
复制
已复制
已保存差异
原始文本
打开文件
/** @module hubspot/upload */ /// <reference path="../types/types.js" /> import fsPromises from 'fs/promises' import uploadFolder from '@hubspot/local-dev-lib/cms/uploadFolder' import { deleteFile, getDirectoryContentsByPath } from '@hubspot/local-dev-lib/api/fileMapper' import { setLogLevel, LOG_LEVEL } from '@hubspot/local-dev-lib/logger' import { isAllowedExtension } from '@hubspot/local-dev-lib/path' import { createIgnoreFilter } from '@hubspot/local-dev-lib/ignoreRules' import { walk } from '@hubspot/local-dev-lib/fs' import * as ui from '../utils/ui.js' import { getThemeOptions } from '../utils/options.js' import { throwErrorIfMissingScope } from './auth/scopes.js' import ora from 'ora' import chalk from 'chalk' import checkbox from '@inquirer/checkbox' import confirm from '@inquirer/confirm' import { getFileList, isFileDir } from '../utils/fs.js' import path from 'path' /** * @type {"draft" | "publish"} */ let cmsMode = 'publish' if (process.env.HUB_MODE === 'draft') { cmsMode = 'draft' } /** * #### Walks the src folder for files, filters them based on ignore filter. * @async * @private * @param {string} src - src folder * @returns {Promise<Array<string>>} src file list */ const getUploadableFileList = async (src) => { /** * @type {Array<string>} */ let filePaths = [] try { filePaths = await walk(src) } catch (error) { console.error(error) } const allowedFiles = filePaths.filter((/** @type {any} */ file) => { if (!isAllowedExtension(file)) { return false } return true // @ts-ignore }).filter(createIgnoreFilter()) return allowedFiles } /** * #### Reads the .cihsignore file and returns the list of files to ignore. * @private * @async * @returns {Promise<string[]>} List of files to ignore. */ async function readCihsIgnore() { return new Promise((resolve) => { const cihsignorePath = path.join(process.cwd(), '.cihsignore'); fsPromises.access(cihsignorePath) .then(() => fsPromises.readFile(cihsignorePath, 'utf8')) .then(ignoreContent => { const ignoredPaths = ignoreContent .split(/\r?\n/) .map(line => line.trim()) .filter(line => line && !line.startsWith('#')); resolve(ignoredPaths); }) .catch(error => { console.error('Error reading .cihsignore file:', error); resolve([]); }); }); } /** * #### Walks the src folder for files, filters them based on ignore filter and CI .cihsignore file. * @async * @private * @param {string} src - src folder * @returns {Promise<Array<string>>} src file list */ const getCiUploadableFileList = async (src) => { /** * @type {Array<string>} */ let filePaths = [] try { filePaths = await walk(src) } catch (error) { console.error(error) } let allowedFiles = filePaths.filter((/** @type {any} */ file) => { if (!isAllowedExtension(file)) { return false } return true // @ts-ignore }).filter(createIgnoreFilter()) async function filterFiles (/** @type {any} */ files) { const ignoredPaths = await readCihsIgnore() return files.filter((/** @type {any} */ file) => !ignoredPaths.some(ignoredPath => file.includes(ignoredPath))) } allowedFiles = await filterFiles(allowedFiles) return allowedFiles } /** * #### upload all HubSpot theme files * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function uploadTheme (config, themeName) { try { const timeStart = ui.startTask('uploadTheme') const cmslibOptions = getThemeOptions() const src = path.join(process.cwd(), cmslibOptions.themeFolder) const dest = themeName const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getUploadableFileList(src) await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'uploadTheme', timeStart }) } catch (error) { console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### delete all templates in theme and reupload them * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function cleanUploadThemeTemplates (config, themeName) { const timeStart = ui.startTask('cleanUploadThemeTemplates') const spinner = ora('Reupload all templates').start() try { const cmslibOptions = getThemeOptions() const src = path.join(process.cwd(), cmslibOptions.themeFolder, 'templates') const dest = path.join(themeName, 'templates') const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.NONE) const uploadableFileList = await getUploadableFileList(src) const filesToDelete = await getDirectoryContentsByPath(portalId, dest) if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file.includes('.html')) { await deleteFile(portalId, path.join(dest, file)) } } } await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) spinner.succeed() ui.endTask({ taskName: 'cleanUploadThemeTemplates', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### clean theme and reupload it * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function cleanUploadTheme (config, themeName) { const timeStart = ui.startTask('cleanUploadTheme') const dest = themeName const spinner = ora(`Clean ${dest} folder before upload`) try { const cmslibOptions = getThemeOptions() const src = path.join(process.cwd(), cmslibOptions.themeFolder) const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getUploadableFileList(src) spinner.start() const filesToDelete = await getDirectoryContentsByPath(portalId, '/') if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file === dest) { await deleteFile(portalId, file) } } } spinner.succeed() await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'cleanUploadTheme', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### CI clean theme upload * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function ciUploadTheme (config, themeName) { const timeStart = ui.startTask('ciUpload') const dest = themeName const spinner = ora(`Clean ${dest} folder before upload`) try { const cmslibOptions = getThemeOptions() const src = path.join(process.cwd(), cmslibOptions.themeFolder) const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getCiUploadableFileList(src) spinner.start() const filesToDelete = await getDirectoryContentsByPath(portalId, '/') if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file === dest) { await deleteFile(portalId, file) } } } spinner.succeed() await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'ciUpload', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### prepare file choices for prompt * @private * @param {Array<FILE_LIST>} files - hubdb files * @returns {Array<{name:string, value:{path:string, name:string, label:string}}>} files choices */ function prepareFileChoices (files) { const fileChoices = [] for (const file of files) { fileChoices.push({ name: file.name, value: { path: file.path, name: file.name, label: file.name.slice(0, -7) } }) } return fileChoices } /** * #### select standalome modules to upload * @async * @private * @param {Array<FILE_LIST>} dirs - files * @returns {Promise<Array<{path:string, name:string, label:string}>>} selected files */ async function selectModules (dirs) { const selectFiles = { message: 'Pick modules:', choices: prepareFileChoices(dirs), pageSize: 5, loop: false } const confirmPortal = (/** @type {any} */ selectedFiles) => { const filesNameList = [] for (const file of selectedFiles) { filesNameList.push(file.name) } if (filesNameList.length === 1) { return { message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} module?` } } else { return { message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} modules?` } } } // select files let selectedTables = await checkbox(selectFiles) if (!selectedTables.length) { console.log(chalk.yellow('No modules selected')) process.exit(0) } // confirm selection let confirmed = await confirm(confirmPortal(selectedTables)) if (!confirmed) { // try again one more time selectedTables = await checkbox(selectFiles) if (!selectedTables.length) { console.log(chalk.yellow('No modules selected')) process.exit(0) } confirmed = await confirm(confirmPortal(selectedTables)) if (!confirmed) { process.exit(0) } } return selectedTables } /** * #### upload module to HubSpot * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @returns undefined */ async function uploadSelectedModules (config) { try { const timeStart = ui.startTask('uploadModules') const modulesToUpload = await getFileList(path.normalize('standalone-modules/*.module'), { objectMode: true, onlyDirectories: true, deep: 1 }) const selectedModules = await selectModules(modulesToUpload) const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) for (const module of selectedModules) { const src = module.path const dest = module.name if (await isFileDir(src) === false) { throw new Error(`${chalk.red('Error')}: Module ${chalk.green(src)} does not exist`) } const uploadableFileList = await getUploadableFileList(src) await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) } ui.endTask({ taskName: 'uploadModules', timeStart }) } catch (error) { console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } export { uploadTheme, cleanUploadThemeTemplates, cleanUploadTheme, ciUploadTheme, uploadSelectedModules }
更改后文本
打开文件
/** @module hubspot/upload */ /// <reference path="../types/types.js" /> import fsPromises from 'fs/promises' import uploadFolder from '@hubspot/local-dev-lib/cms/uploadFolder' import { deleteFile, getDirectoryContentsByPath } from '@hubspot/local-dev-lib/api/fileMapper' import { setLogLevel, LOG_LEVEL } from '@hubspot/local-dev-lib/logger' import { isAllowedExtension } from '@hubspot/local-dev-lib/path' import { createIgnoreFilter } from '@hubspot/local-dev-lib/ignoreRules' import { walk } from '@hubspot/local-dev-lib/fs' import * as ui from '../utils/ui.js' import { getThemeOptions } from '../utils/options.js' import { throwErrorIfMissingScope } from './auth/scopes.js' import ora from 'ora' import chalk from 'chalk' import checkbox from '@inquirer/checkbox' import confirm from '@inquirer/confirm' import { getFileList, isFileDir } from '../utils/fs.js' /** * @type {"draft" | "publish"} */ let cmsMode = 'publish' if (process.env.HUB_MODE === 'draft') { cmsMode = 'draft' } /** * #### Walks the src folder for files, filters them based on ignore filter. * @async * @private * @param {string} src - src folder * @returns {Promise<Array<string>>} src file list */ const getUploadableFileList = async (src) => { /** * @type {Array<string>} */ let filePaths = [] try { filePaths = await walk(src) } catch (error) { console.error(error) } const allowedFiles = filePaths.filter((/** @type {any} */ file) => { if (!isAllowedExtension(file)) { return false } return true // @ts-ignore }).filter(createIgnoreFilter()) return allowedFiles } /** * #### Reads the .cihsignore file and returns the list of files to ignore. * @private * @async * @returns {Promise<string[]>} List of files to ignore. */ async function readCihsIgnore () { try { if (await isFileDir(`${process.cwd()}/.cihsignore`)) { const ignoreContent = await fsPromises.readFile(`${process.cwd()}/.cihsignore`, 'utf8') return ignoreContent.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('#')) } else { return [] } } catch (error) { console.error('Error reading .cihsignore file:', error) return [] } } /** * #### Walks the src folder for files, filters them based on ignore filter and CI .cihsignore file. * @async * @private * @param {string} src - src folder * @returns {Promise<Array<string>>} src file list */ const getCiUploadableFileList = async (src) => { /** * @type {Array<string>} */ let filePaths = [] try { filePaths = await walk(src) } catch (error) { console.error(error) } let allowedFiles = filePaths.filter((/** @type {any} */ file) => { if (!isAllowedExtension(file)) { return false } return true // @ts-ignore }).filter(createIgnoreFilter()) async function filterFiles (/** @type {any} */ files) { const ignoredPaths = await readCihsIgnore() return files.filter((/** @type {any} */ file) => !ignoredPaths.some(ignoredPath => file.includes(ignoredPath))) } allowedFiles = await filterFiles(allowedFiles) return allowedFiles } /** * #### upload all HubSpot theme files * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function uploadTheme (config, themeName) { try { const timeStart = ui.startTask('uploadTheme') const cmslibOptions = getThemeOptions() const src = `${process.cwd()}/${cmslibOptions.themeFolder}` const dest = themeName const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getUploadableFileList(src) await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'uploadTheme', timeStart }) } catch (error) { console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### delete all templates in theme and reupload them * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function cleanUploadThemeTemplates (config, themeName) { const timeStart = ui.startTask('cleanUploadThemeTemplates') const spinner = ora('Reupload all templates').start() try { const cmslibOptions = getThemeOptions() const src = `${process.cwd()}/${cmslibOptions.themeFolder}/templates` const dest = `${themeName}/templates` const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.NONE) const uploadableFileList = await getUploadableFileList(src) const filesToDelete = await getDirectoryContentsByPath(portalId, dest) if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file.includes('.html')) { await deleteFile(portalId, `${dest}/${file}`) } } } await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) spinner.succeed() ui.endTask({ taskName: 'cleanUploadThemeTemplates', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### clean theme and reupload it * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function cleanUploadTheme (config, themeName) { const timeStart = ui.startTask('cleanUploadTheme') const dest = themeName const spinner = ora(`Clean ${dest} folder before upload`) try { const cmslibOptions = getThemeOptions() const src = `${process.cwd()}/${cmslibOptions.themeFolder}` const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getUploadableFileList(src) spinner.start() const filesToDelete = await getDirectoryContentsByPath(portalId, '/') if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file === dest) { await deleteFile(portalId, file) } } } spinner.succeed() await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'cleanUploadTheme', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### CI clean theme upload * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @param {string} themeName - theme name * @returns undefined */ async function ciUploadTheme (config, themeName) { const timeStart = ui.startTask('ciUpload') const dest = themeName const spinner = ora(`Clean ${dest} folder before upload`) try { const cmslibOptions = getThemeOptions() const src = `${process.cwd()}/${cmslibOptions.themeFolder}` const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) const uploadableFileList = await getCiUploadableFileList(src) spinner.start() const filesToDelete = await getDirectoryContentsByPath(portalId, '/') if (filesToDelete !== undefined && filesToDelete.data.children.length > 0) { for await (const file of filesToDelete.data.children) { // @ts-ignore if (file === dest) { await deleteFile(portalId, file) } } } spinner.succeed() await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) ui.endTask({ taskName: 'ciUpload', timeStart }) } catch (error) { spinner.fail() console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } /** * #### prepare file choices for prompt * @private * @param {Array<FILE_LIST>} files - hubdb files * @returns {Array<{name:string, value:{path:string, name:string, label:string}}>} files choices */ function prepareFileChoices (files) { const fileChoices = [] for (const file of files) { fileChoices.push({ name: file.name, value: { path: file.path, name: file.name, label: file.name.slice(0, -7) } }) } return fileChoices } /** * #### select standalome modules to upload * @async * @private * @param {Array<FILE_LIST>} dirs - files * @returns {Promise<Array<{path:string, name:string, label:string}>>} selected files */ async function selectModules (dirs) { const selectFiles = { message: 'Pick modules:', choices: prepareFileChoices(dirs), pageSize: 5, loop: false } const confirmPortal = (/** @type {any} */ selectedFiles) => { const filesNameList = [] for (const file of selectedFiles) { filesNameList.push(file.name) } if (filesNameList.length === 1) { return { message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} module?` } } else { return { message: `Continue with ${chalk.cyan.bold(filesNameList.join(','))} modules?` } } } // select files let selectedTables = await checkbox(selectFiles) if (!selectedTables.length) { console.log(chalk.yellow('No modules selected')) process.exit(0) } // confirm selection let confirmed = await confirm(confirmPortal(selectedTables)) if (!confirmed) { // try again one more time selectedTables = await checkbox(selectFiles) if (!selectedTables.length) { console.log(chalk.yellow('No modules selected')) process.exit(0) } confirmed = await confirm(confirmPortal(selectedTables)) if (!confirmed) { process.exit(0) } } return selectedTables } /** * #### upload module to HubSpot * @async * @param {HUBSPOT_AUTH_CONFIG} config - hubspot authentication config * @returns undefined */ async function uploadSelectedModules (config) { try { const timeStart = ui.startTask('uploadModules') const modulesToUpload = await getFileList('standalone-modules/*.module', { objectMode: true, onlyDirectories: true, deep: 1 }) const selectedModules = await selectModules(modulesToUpload) const portalId = config.portals[0].portalId throwErrorIfMissingScope(config, 'design_manager') setLogLevel(LOG_LEVEL.LOG) for (const module of selectedModules) { const src = module.path const dest = module.name if (await isFileDir(src) === false) { throw new Error(`${chalk.red('Error')}: Module ${chalk.green(src)} does not exist`) } const uploadableFileList = await getUploadableFileList(src) await uploadFolder.uploadFolder( portalId, src, dest, { overwrite: false }, { saveOutput: true, convertFields: false }, uploadableFileList, cmsMode ) } ui.endTask({ taskName: 'uploadModules', timeStart }) } catch (error) { console.error(chalk.red('Error:')) console.error(error.message) process.exitCode = 1 if (process.env.DEBUG_MODE === 'debug') { console.error(error) process.exitCode = 1 } } } export { uploadTheme, cleanUploadThemeTemplates, cleanUploadTheme, ciUploadTheme, uploadSelectedModules }
查找差异