Diff
checker
텍스트
텍스트
이미지
문서
Excel
폴더
Legal
Enterprise
데스크톱
요금제
로그인
데스크톱 앱 다운로드
텍스트 비교
두 텍스트 파일의 차이점을 찾아보세요
도구
기록
실시간 편집
변경 없는 행 숨기기
줄바꿈 비활성화
레이아웃
나란히 보기
합쳐 보기
비교 단위
스마트
단어
글자
구문 강조
언어 선택
제외
텍스트 변환
첫 변경으로
수정
Diffchecker Desktop
가장 안전하게 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 }
비교하기