From 48adf282c6b227d3dc574faf2ed1523837c03378 Mon Sep 17 00:00:00 2001 From: Ivan Kiral Date: Fri, 6 Dec 2024 09:39:56 +0100 Subject: [PATCH 1/4] add headers to webhook data --- .../backupRestore/backupRestoreEntities/entities/webhooks.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/backupRestore/backupRestoreEntities/entities/webhooks.ts b/src/modules/backupRestore/backupRestoreEntities/entities/webhooks.ts index 311eba1e..00bbccdb 100644 --- a/src/modules/backupRestore/backupRestoreEntities/entities/webhooks.ts +++ b/src/modules/backupRestore/backupRestoreEntities/entities/webhooks.ts @@ -31,6 +31,7 @@ export const webhooksEntity = { secret: webhook.secret, url: webhook.url, enabled: webhook.enabled, + headers: webhook.headers, delivery_triggers: transformReferences( webhook.delivery_triggers, simplifyContext(context, [ From 66668d78181bbc1ccefbf33ef6a0c9ef847129fe Mon Sep 17 00:00:00 2001 From: Ivan Kiral Date: Fri, 6 Dec 2024 10:13:00 +0100 Subject: [PATCH 2/4] fix filename serialization for backup command --- src/modules/backupRestore/backup.ts | 4 ++-- .../migrations/utils/migrationUtils.ts | 11 ++-------- src/modules/sync/generateSyncModel.ts | 4 ++-- src/utils/files.ts | 22 +++++++++++++++---- tests/unit/utils/files.test.ts | 20 +++++++++++++++++ 5 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 tests/unit/utils/files.test.ts diff --git a/src/modules/backupRestore/backup.ts b/src/modules/backupRestore/backup.ts index e8dad6ef..13e9bd89 100644 --- a/src/modules/backupRestore/backup.ts +++ b/src/modules/backupRestore/backup.ts @@ -8,7 +8,7 @@ import * as fs from "fs"; import packageFile from "../../../package.json" with { type: "json" }; import { logInfo, LogOptions } from "../../log.js"; import { createClient } from "../../utils/client.js"; -import { serializeDateForFileName } from "../../utils/files.js"; +import { DateLevel, serializeDateForFileName } from "../../utils/files.js"; import { serially } from "../../utils/requests.js"; import { assetFoldersEntity } from "./backupRestoreEntities/entities/assetFolders.js"; import { assetsEntity } from "./backupRestoreEntities/entities/assets.js"; @@ -90,7 +90,7 @@ export const backupEnvironmentInternal = async ( const now = new Date(); const fileName = params.fileName - ?? `${serializeDateForFileName(now)}-backup-${params.environmentId}.zip`; + ?? `${serializeDateForFileName(now, DateLevel.Minute)}-backup-${params.environmentId}.zip`; const outputStream = fs.createWriteStream(fileName); const archive = archiver("zip"); diff --git a/src/modules/migrations/utils/migrationUtils.ts b/src/modules/migrations/utils/migrationUtils.ts index 0307bce3..10b7db83 100644 --- a/src/modules/migrations/utils/migrationUtils.ts +++ b/src/modules/migrations/utils/migrationUtils.ts @@ -7,6 +7,7 @@ import chalk from "chalk"; import { match, P } from "ts-pattern"; import { logError, logInfo, LogOptions } from "../../../log.js"; +import { DateLevel, serializeDateForFileName } from "../../../utils/files.js"; import { seriallyReduce } from "../../../utils/requests.js"; import { isMigrationModule, Migration, MigrationModuleType, MigrationOrder } from "../models/migration.js"; import { MigrationOperation, MigrationStatus } from "../models/status.js"; @@ -15,16 +16,8 @@ import { WithErr } from "./errUtils.js"; import { orderComparator } from "./orderUtils.js"; import { createMigrationStatus } from "./statusUtils.js"; -export const formatDateForFileName = (date: Date) => - `${date.getUTCFullYear()}-` - + `${("0" + (date.getUTCMonth() + 1)).slice(-2)}-` - + `${("0" + date.getUTCDate()).slice(-2)}-` - + `${("0" + date.getUTCHours()).slice(-2)}-` - + `${("0" + date.getUTCMinutes()).slice(-2)}-` - + `${("0" + date.getUTCSeconds()).slice(-2)}-`; - export const getMigrationName = (name: string, type: MigrationModuleType, prefix: Date | string | undefined) => - `${prefix instanceof Date ? formatDateForFileName(prefix) : prefix ?? ""}${name}.${type}`; + `${prefix instanceof Date ? `${serializeDateForFileName(prefix, DateLevel.Second)}-` : prefix ?? ""}${name}.${type}`; export const generateTypescriptMigration = (order: Date | number | undefined): string => `import { MigrationModule } from "@kontent-ai/data-ops"; diff --git a/src/modules/sync/generateSyncModel.ts b/src/modules/sync/generateSyncModel.ts index 3622ff91..fb1d4ca1 100644 --- a/src/modules/sync/generateSyncModel.ts +++ b/src/modules/sync/generateSyncModel.ts @@ -16,7 +16,7 @@ import * as path from "path"; import packageJson from "../../../package.json" with { type: "json" }; import { logInfo, LogOptions } from "../../log.js"; -import { serializeDateForFileName } from "../../utils/files.js"; +import { DateLevel, serializeDateForFileName } from "../../utils/files.js"; import { notNullOrUndefined } from "../../utils/typeguards.js"; import { syncEntityChoices, SyncEntityName } from "./constants/entities.js"; import { @@ -168,7 +168,7 @@ export const saveSyncModel = async (params: SaveModelParams) => { generatedFromEnvironmentId: params.environmentId, }, }; - const folderName = params.folderName ?? `${serializeDateForFileName(now)}-${params.environmentId}`; + const folderName = params.folderName ?? `${serializeDateForFileName(now, DateLevel.Minute)}-${params.environmentId}`; logInfo(params, "standard", `Saving the model into a folder "${chalk.yellow(folderName)}".`); diff --git a/src/utils/files.ts b/src/utils/files.ts index 63c25114..29dd20e3 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -1,4 +1,18 @@ -export const serializeDateForFileName = (date: Date) => - `${date.getUTCFullYear()}-${ - date.getUTCMonth() + 1 - }-${date.getUTCDate()}-${date.getUTCHours()}-${date.getUTCMinutes()}`; +export enum DateLevel { + Year = 0, + Month = 1, + Day = 2, + Hour = 3, + Minute = 4, + Second = 5, +} + +export const serializeDateForFileName = (date: Date, level: DateLevel) => + [ + date.getUTCFullYear(), + ...level >= DateLevel.Month ? [("0" + (date.getUTCMonth() + 1)).slice(-2)] : [], + ...level >= DateLevel.Day ? [("0" + date.getUTCDate()).slice(-2)] : [], + ...level >= DateLevel.Hour ? [("0" + date.getUTCHours()).slice(-2)] : [], + ...level >= DateLevel.Minute ? [("0" + date.getUTCMinutes()).slice(-2)] : [], + ...level >= DateLevel.Second ? [("0" + date.getUTCSeconds()).slice(-2)] : [], + ].join("-"); diff --git a/tests/unit/utils/files.test.ts b/tests/unit/utils/files.test.ts new file mode 100644 index 00000000..56cee577 --- /dev/null +++ b/tests/unit/utils/files.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from "vitest"; + +import { DateLevel, serializeDateForFileName } from "../../../src/utils/files.js"; + +describe("serializeDateForFileName", () => { + it.each([ + { result: "2025", level: DateLevel[DateLevel.Year] }, + { result: "2025-02", level: DateLevel[DateLevel.Month] }, + { result: "2025-02-07", level: DateLevel[DateLevel.Day] }, + { result: "2025-02-07-15", level: DateLevel[DateLevel.Hour] }, + { result: "2025-02-07-15-08", level: DateLevel[DateLevel.Minute] }, + { result: "2025-02-07-15-08-40", level: DateLevel[DateLevel.Second] }, + ])( + `correctly serializes date 2025-02-07T15:08:40Z to $result with DateLevel $level`, + ({ result, level }) => { + const date = new Date("2025-02-07T15:08:40Z"); + expect(serializeDateForFileName(date, DateLevel[level as keyof typeof DateLevel])).toEqual(result); + }, + ); +}); From 75a2e2a08d960a92cc86ccff337b5cce61614cfe Mon Sep 17 00:00:00 2001 From: Jiri Lojda Date: Tue, 7 Jan 2025 13:54:55 +0100 Subject: [PATCH 3/4] Refactor serializeDateForFileName --- src/modules/migrations/add.ts | 6 +----- src/utils/files.ts | 25 +++++++++++++++++-------- src/utils/number.ts | 11 +++++++++++ tests/unit/utils/number.test.ts | 21 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 src/utils/number.ts create mode 100644 tests/unit/utils/number.test.ts diff --git a/src/modules/migrations/add.ts b/src/modules/migrations/add.ts index f817e6b4..89af253a 100644 --- a/src/modules/migrations/add.ts +++ b/src/modules/migrations/add.ts @@ -3,6 +3,7 @@ import { existsSync } from "fs"; import * as path from "path"; import { logInfo, LogOptions } from "../../log.js"; +import { padWithLeadingZeros } from "../../utils/number.js"; import { MigrationModuleType } from "./models/migration.js"; import { handleErr } from "./utils/errUtils.js"; import { createFolder, saveFile } from "./utils/fileUtils.js"; @@ -56,11 +57,6 @@ export const addMigration = async (params: AddMigrationParams) => { ); }; -const padWithLeadingZeros = (order: number, numberOfZeros: number | undefined) => - numberOfZeros - ? order.toString().padStart(numberOfZeros, "0") - : order.toString(); - type TimestampOrOrderParams = | Readonly<{ timestamp: true }> | Readonly<{ timestamp?: false } & OrderParams>; diff --git a/src/utils/files.ts b/src/utils/files.ts index 29dd20e3..ff4001a5 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -1,3 +1,5 @@ +import { padWithLeadingZeros } from "./number.js"; + export enum DateLevel { Year = 0, Month = 1, @@ -8,11 +10,18 @@ export enum DateLevel { } export const serializeDateForFileName = (date: Date, level: DateLevel) => - [ - date.getUTCFullYear(), - ...level >= DateLevel.Month ? [("0" + (date.getUTCMonth() + 1)).slice(-2)] : [], - ...level >= DateLevel.Day ? [("0" + date.getUTCDate()).slice(-2)] : [], - ...level >= DateLevel.Hour ? [("0" + date.getUTCHours()).slice(-2)] : [], - ...level >= DateLevel.Minute ? [("0" + date.getUTCMinutes()).slice(-2)] : [], - ...level >= DateLevel.Second ? [("0" + date.getUTCSeconds()).slice(-2)] : [], - ].join("-"); + createDateParts(date) + .slice(0, level + 1) + .join("-"); + +const createDateParts = (date: Date) => + Object.values( + { + [DateLevel.Year]: date.getUTCFullYear().toString(), + [DateLevel.Month]: padWithLeadingZeros(date.getUTCMonth() + 1, 2), + [DateLevel.Day]: padWithLeadingZeros(date.getUTCDate(), 2), + [DateLevel.Hour]: padWithLeadingZeros(date.getUTCHours(), 2), + [DateLevel.Minute]: padWithLeadingZeros(date.getUTCMinutes(), 2), + [DateLevel.Second]: padWithLeadingZeros(date.getUTCSeconds(), 2), + } as const satisfies Record, + ); diff --git a/src/utils/number.ts b/src/utils/number.ts new file mode 100644 index 00000000..b0a8f0f6 --- /dev/null +++ b/src/utils/number.ts @@ -0,0 +1,11 @@ +/** + * Pads a given positive number with leading zeros up to the specified length. + * + * @param {number} num - The positive number to pad. Must be greater than or equal to 0. + * @param {number | undefined} numberOfZeros - The total length of the resulting string, including leading zeros. If undefined, the number is returned as is. + * @returns {string} The number as a string, padded with leading zeros if specified. + */ +export const padWithLeadingZeros = (num: number, numberOfZeros: number | undefined): string => + numberOfZeros + ? num.toString().padStart(numberOfZeros, "0") + : num.toString(); diff --git a/tests/unit/utils/number.test.ts b/tests/unit/utils/number.test.ts new file mode 100644 index 00000000..e83c4332 --- /dev/null +++ b/tests/unit/utils/number.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from "vitest"; + +import { padWithLeadingZeros } from "../../../src/utils/number.js"; + +describe("padWithLeadingZeros", () => { + it.each( + [ + { input: [5, 3], expected: "005" }, + { input: [42, 5], expected: "00042" }, + { input: [0, 4], expected: "0000" }, + { input: [123, 2], expected: "123" }, + { input: [4567, 4], expected: "4567" }, + { input: [5, 0], expected: "5" }, + { input: [8, undefined], expected: "8" }, + { input: [123, undefined], expected: "123" }, + ] as const, + )("should return $expected for input $input", ({ input, expected }) => { + const [num, leadingZeros] = input; + expect(padWithLeadingZeros(num, leadingZeros)).toBe(expected); + }); +}); From 4ec949c2c2a3c7ff6079a75ebac2b91eed8d4633 Mon Sep 17 00:00:00 2001 From: Ivan Kiral Date: Tue, 7 Jan 2025 12:42:01 +0100 Subject: [PATCH 4/4] 2.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8a8238f1..bcf2b20e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@kontent-ai/data-ops", - "version": "2.2.2", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@kontent-ai/data-ops", - "version": "2.2.2", + "version": "2.3.0", "license": "MIT", "dependencies": { "@kontent-ai/core-sdk": "^10.8.0", diff --git a/package.json b/package.json index e62daa0d..8a3784eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kontent-ai/data-ops", - "version": "2.2.2", + "version": "2.3.0", "description": "", "type": "module", "scripts": {