Diff
checker
Text
Text
Bilder
Dokumente
Excel
Ordner
Legal
Enterprise
Desktop-App
Preise
Einloggen
Diffchecker Desktop herunterladen
Texte vergleichen
Finde den Unterschied zwischen zwei Textdateien
Werkzeuge
Verlauf
Live-Editor
Gleiches ausblenden
Zeilenumbruch aus
Ansicht
Zweispaltig
Einspaltig
Vergleichsgenauigkeit
Intelligent
Wort
Zeichen
Syntaxhervorhebung
Syntax auswählen
Ignorieren
Text umwandeln
Zur ersten Änderung
Eingabe bearbeiten
Diffchecker Desktop
Der sicherste Weg, Diffchecker zu nutzen. Hol dir die Desktop-App: Deine Diffs verlassen nie deinen Computer!
Desktop holen
resultify-hubspot-cms-windows
Erstellt
vor 2 Jahren
Diff läuft nie ab
Löschen
Exportieren
Teilen
Erklären
60 Entfernungen
Zeilen
Gesamt
Entfernt
Zeichen
Gesamt
Entfernt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
424 Zeilen
Kopieren
38 Hinzufügungen
Zeilen
Gesamt
Hinzugefügt
Zeichen
Gesamt
Hinzugefügt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
412 Zeilen
Kopieren
/** @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'
Kopieren
Kopiert
Kopieren
Kopiert
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.
*/
*/
Kopieren
Kopiert
Kopieren
Kopiert
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()
Kopieren
Kopiert
Kopieren
Kopiert
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()
Kopieren
Kopiert
Kopieren
Kopiert
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')) {
Kopieren
Kopiert
Kopieren
Kopiert
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()
Kopieren
Kopiert
Kopieren
Kopiert
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()
Kopieren
Kopiert
Kopieren
Kopiert
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')
Kopieren
Kopiert
Kopieren
Kopiert
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 }
Kopieren
Kopiert
Kopieren
Kopiert
Gespeicherte Diffs
Originaltext
Datei öffnen
/** @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 }
Bearbeitung
Datei öffnen
/** @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 }
Unterschied finden