From feaf34c124ab2263fe3de6e589d9107bfac4e197 Mon Sep 17 00:00:00 2001 From: garronej Date: Thu, 6 Apr 2023 16:38:13 +0200 Subject: [PATCH 01/10] Include the theme version in kcContext --- src/bin/keycloakify/BuildOptions.ts | 4 ++-- .../ftl_object_to_js_code_declaring_an_object.ftl | 3 ++- src/bin/keycloakify/generateFtl/generateFtl.ts | 4 +++- src/bin/keycloakify/generateJavaStackFiles.ts | 8 ++++---- src/bin/keycloakify/generateKeycloakThemeResources.ts | 1 + src/bin/keycloakify/keycloakify.ts | 2 +- src/bin/keycloakify/parsedPackageJson.ts | 4 ++-- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/bin/keycloakify/BuildOptions.ts b/src/bin/keycloakify/BuildOptions.ts index aa68cd41..30831022 100644 --- a/src/bin/keycloakify/BuildOptions.ts +++ b/src/bin/keycloakify/BuildOptions.ts @@ -13,7 +13,7 @@ export type BuildOptions = BuildOptions.Standalone | BuildOptions.ExternalAssets export namespace BuildOptions { export type Common = { isSilent: boolean; - version: string; + themeVersion: string; themeName: string; extraLoginPages: string[] | undefined; extraAccountPages: string[] | undefined; @@ -139,7 +139,7 @@ export function readBuildOptions(params: { projectDirPath: string; isExternalAss .join(".") ?? fallbackGroupId) + ".keycloak" ); })(), - "version": process.env.KEYCLOAKIFY_VERSION ?? version, + "themeVersion": process.env.KEYCLOAKIFY_THEME_VERSION ?? process.env.KEYCLOAKIFY_VERSION ?? version ?? "0.0.0", "extraLoginPages": [...(extraPages ?? []), ...(extraLoginPages ?? [])], extraAccountPages, extraThemeProperties, diff --git a/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl b/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl index ffb9ee97..67c90f19 100644 --- a/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +++ b/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl @@ -118,8 +118,9 @@ }; - out["pageId"] = "PAGE_ID_xIgLsPgGId9D8e"; out["keycloakifyVersion"] = "KEYCLOAKIFY_VERSION_xEdKd3xEdr"; + out["themeVersion"] = "KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx"; + out["pageId"] = "PAGE_ID_xIgLsPgGId9D8e"; return out; diff --git a/src/bin/keycloakify/generateFtl/generateFtl.ts b/src/bin/keycloakify/generateFtl/generateFtl.ts index 48257180..be79ef37 100644 --- a/src/bin/keycloakify/generateFtl/generateFtl.ts +++ b/src/bin/keycloakify/generateFtl/generateFtl.ts @@ -18,6 +18,7 @@ export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.Ex export namespace BuildOptionsLike { export type Common = { customUserAttributes: string[]; + themeVersion: string; }; export type Standalone = Common & { @@ -130,7 +131,8 @@ export function generateFtlFilesCodeFactory(params: { "CUSTOM_USER_ATTRIBUTES_eKsIY4ZsZ4xeM", buildOptions.customUserAttributes.length === 0 ? "" : ", " + buildOptions.customUserAttributes.map(name => `"${name}"`).join(", ") ) - .replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion), + .replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion) + .replace("KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx", buildOptions.themeVersion), "": [ "<#if scripts??>", " <#list scripts as script>", diff --git a/src/bin/keycloakify/generateJavaStackFiles.ts b/src/bin/keycloakify/generateJavaStackFiles.ts index 890cc44c..0ee215df 100644 --- a/src/bin/keycloakify/generateJavaStackFiles.ts +++ b/src/bin/keycloakify/generateJavaStackFiles.ts @@ -9,7 +9,7 @@ export type BuildOptionsLike = { themeName: string; groupId: string; artifactId?: string; - version: string; + themeVersion: string; }; { @@ -26,7 +26,7 @@ export function generateJavaStackFiles(params: { jarFilePath: string; } { const { - buildOptions: { groupId, themeName, version, artifactId }, + buildOptions: { groupId, themeName, themeVersion, artifactId }, keycloakThemeBuildingDirPath, doBundlesEmailTemplate } = params; @@ -43,7 +43,7 @@ export function generateJavaStackFiles(params: { ` 4.0.0`, ` ${groupId}`, ` ${artifactId}`, - ` ${version}`, + ` ${themeVersion}`, ` ${artifactId}`, ` `, `` @@ -83,6 +83,6 @@ export function generateJavaStackFiles(params: { } return { - "jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${artifactId}-${version}.jar`) + "jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${artifactId}-${themeVersion}.jar`) }; } diff --git a/src/bin/keycloakify/generateKeycloakThemeResources.ts b/src/bin/keycloakify/generateKeycloakThemeResources.ts index 8d12de60..870e9230 100644 --- a/src/bin/keycloakify/generateKeycloakThemeResources.ts +++ b/src/bin/keycloakify/generateKeycloakThemeResources.ts @@ -20,6 +20,7 @@ export namespace BuildOptionsLike { extraThemeProperties?: string[]; isSilent: boolean; customUserAttributes: string[]; + themeVersion: string; }; export type Standalone = Common & { diff --git a/src/bin/keycloakify/keycloakify.ts b/src/bin/keycloakify/keycloakify.ts index 228f7ae2..2640de18 100644 --- a/src/bin/keycloakify/keycloakify.ts +++ b/src/bin/keycloakify/keycloakify.ts @@ -63,7 +63,7 @@ export async function main() { logger.log("🫶 Let keycloakify do its thang"); await jar({ "rootPath": pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources"), - "version": buildOptions.version, + "version": buildOptions.themeVersion, "groupId": buildOptions.groupId, "artifactId": buildOptions.artifactId, "targetPath": jarFilePath diff --git a/src/bin/keycloakify/parsedPackageJson.ts b/src/bin/keycloakify/parsedPackageJson.ts index 4dc3c6f0..6ee593fd 100644 --- a/src/bin/keycloakify/parsedPackageJson.ts +++ b/src/bin/keycloakify/parsedPackageJson.ts @@ -8,7 +8,7 @@ export const bundlers = ["mvn", "keycloakify", "none"] as const; export type Bundler = (typeof bundlers)[number]; export type ParsedPackageJson = { name: string; - version: string; + version?: string; homepage?: string; keycloakify?: { /** @deprecated: use extraLoginPages instead */ @@ -30,7 +30,7 @@ export type ParsedPackageJson = { export const zParsedPackageJson = z.object({ "name": z.string(), - "version": z.string(), + "version": z.string().optional(), "homepage": z.string().optional(), "keycloakify": z .object({ From 2d055217897fe8b41ee2da2e655c7204beb7fbb4 Mon Sep 17 00:00:00 2001 From: Waldemar Reusch Date: Thu, 6 Apr 2023 21:34:20 +0200 Subject: [PATCH 02/10] fix(jar): fix empty jar --- src/bin/tools/jar.ts | 2 +- src/bin/tools/walk.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/tools/jar.ts b/src/bin/tools/jar.ts index 4964ed72..a87e9048 100644 --- a/src/bin/tools/jar.ts +++ b/src/bin/tools/jar.ts @@ -48,7 +48,7 @@ export async function jarStream({ groupId, artifactId, version, asyncPathGenerat for await (const entry of asyncPathGeneratorFn()) { if ("buffer" in entry) { zipFile.addBuffer(entry.buffer, entry.zipPath); - } else if ("fsPath" in entry && entry.fsPath.endsWith(sep)) { + } else if ("fsPath" in entry && !entry.fsPath.endsWith(sep)) { zipFile.addFile(entry.fsPath, entry.zipPath); } } diff --git a/src/bin/tools/walk.ts b/src/bin/tools/walk.ts index f7c4dee0..5c1cd739 100644 --- a/src/bin/tools/walk.ts +++ b/src/bin/tools/walk.ts @@ -1,9 +1,9 @@ import { readdir } from "fs/promises"; -import { resolve } from "path"; +import { resolve, sep } from "path"; /** * Asynchronously and recursively walk a directory tree, yielding every file and directory - * found + * found. Directory paths will _always_ end with a path separator. * * @param root the starting directory * @returns AsyncGenerator @@ -12,8 +12,8 @@ export default async function* walk(root: string): AsyncGenerator Date: Thu, 6 Apr 2023 22:02:45 +0200 Subject: [PATCH 03/10] chore(jar): add jar test --- test/bin/jar.spec.ts | 54 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/test/bin/jar.spec.ts b/test/bin/jar.spec.ts index 7f50637c..939060d4 100644 --- a/test/bin/jar.spec.ts +++ b/test/bin/jar.spec.ts @@ -1,7 +1,12 @@ -import { jarStream, type ZipEntryGenerator } from "keycloakify/bin/tools/jar"; +import jar, { jarStream, type ZipEntryGenerator } from "keycloakify/bin/tools/jar"; import { fromBuffer, Entry, ZipFile } from "yauzl"; -import { it, describe, assert } from "vitest"; +import { it, describe, assert, afterAll } from "vitest"; import { Readable } from "stream"; +import { tmpdir } from "os"; +import { mkdtemp, cp, mkdir, rm } from "fs/promises"; +import path from "path"; +import { createReadStream } from "fs"; +import walk from "keycloakify/bin/tools/walk"; type AsyncIterable = { [Symbol.asyncIterator](): AsyncIterableIterator; @@ -17,7 +22,7 @@ async function readToBuffer(stream: NodeJS.ReadableStream) { return Buffer.concat(await arrayFromAsync(stream as AsyncIterable)); } -function unzip(buffer: Buffer) { +function unzipBuffer(buffer: Buffer) { return new Promise((resolve, reject) => fromBuffer(buffer, { lazyEntries: true }, (err, zipFile) => { if (err !== null) { @@ -57,15 +62,23 @@ function readAll(zipFile: ZipFile): Promise> { } describe("jar", () => { + + const coords = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3" } + + const tmpDirs: string[] = [] + + // afterAll(async () => { + // await Promise.all(tmpDirs.map(dir => rm(dir, { force: true, recursive: true }))); + // }); + it("creates jar artifacts without error", async () => { async function* mockFiles(): ZipEntryGenerator { yield { zipPath: "foo", buffer: Buffer.from("foo") }; } - const opts = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3", asyncPathGeneratorFn: mockFiles }; - const zipped = await jarStream(opts); + const zipped = await jarStream({ ...coords, asyncPathGeneratorFn: mockFiles }); const buffered = await readToBuffer(zipped.outputStream); - const unzipped = await unzip(buffered); + const unzipped = await unzipBuffer(buffered); const entries = await readAll(unzipped); assert.equal(entries.size, 3); @@ -83,4 +96,33 @@ describe("jar", () => { assert.isOk(pomProperties?.includes("someGroupId")); assert.isOk(pomProperties?.includes("someArtifactId")); }); + + it("creates a jar from _real_ files without error", async () => { + + const tmp = await mkdtemp(path.join(tmpdir(), "kc-jar-test-")) + tmpDirs.push(tmp) + const rootPath = path.join(tmp, "src") + const targetPath = path.join(tmp, "jar.jar") + await mkdir(rootPath) + + await cp(path.dirname(__dirname), rootPath, { recursive: true }) + + await jar({ ...coords, rootPath, targetPath }) + + const buffered = await readToBuffer(createReadStream(targetPath)); + const unzipped = await unzipBuffer(buffered); + const entries = await readAll(unzipped); + const zipPaths = Array.from(entries.keys()) + + assert.isOk(entries.has("META-INF/MANIFEST.MF")); + assert.isOk(entries.has("META-INF/maven/someGroupId/someArtifactId/pom.properties")); + + for await (const fsPath of walk(rootPath)) { + if (!fsPath.endsWith(path.sep)) { + const rel = path.relative(rootPath, fsPath).replace(path.sep === "/" ? /\//g : /\\/g, "/") + assert.isOk(zipPaths.includes(rel), `missing ${rel} (${rel}, ${zipPaths.join(", ")})`) + } + } + + }) }); From b325b3537f3d51a5efb1715be9184980c61d86db Mon Sep 17 00:00:00 2001 From: Waldemar Reusch Date: Thu, 6 Apr 2023 22:06:14 +0200 Subject: [PATCH 04/10] style: fix formatting --- src/bin/tools/walk.ts | 4 ++-- test/bin/jar.spec.ts | 29 +++++++++++++---------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/bin/tools/walk.ts b/src/bin/tools/walk.ts index 5c1cd739..57c544a6 100644 --- a/src/bin/tools/walk.ts +++ b/src/bin/tools/walk.ts @@ -12,8 +12,8 @@ export default async function* walk(root: string): AsyncGenerator> { } describe("jar", () => { + const coords = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3" }; - const coords = { artifactId: "someArtifactId", groupId: "someGroupId", version: "1.2.3" } - - const tmpDirs: string[] = [] + const tmpDirs: string[] = []; // afterAll(async () => { // await Promise.all(tmpDirs.map(dir => rm(dir, { force: true, recursive: true }))); @@ -98,31 +97,29 @@ describe("jar", () => { }); it("creates a jar from _real_ files without error", async () => { + const tmp = await mkdtemp(path.join(tmpdir(), "kc-jar-test-")); + tmpDirs.push(tmp); + const rootPath = path.join(tmp, "src"); + const targetPath = path.join(tmp, "jar.jar"); + await mkdir(rootPath); - const tmp = await mkdtemp(path.join(tmpdir(), "kc-jar-test-")) - tmpDirs.push(tmp) - const rootPath = path.join(tmp, "src") - const targetPath = path.join(tmp, "jar.jar") - await mkdir(rootPath) + await cp(path.dirname(__dirname), rootPath, { recursive: true }); - await cp(path.dirname(__dirname), rootPath, { recursive: true }) - - await jar({ ...coords, rootPath, targetPath }) + await jar({ ...coords, rootPath, targetPath }); const buffered = await readToBuffer(createReadStream(targetPath)); const unzipped = await unzipBuffer(buffered); const entries = await readAll(unzipped); - const zipPaths = Array.from(entries.keys()) + const zipPaths = Array.from(entries.keys()); assert.isOk(entries.has("META-INF/MANIFEST.MF")); assert.isOk(entries.has("META-INF/maven/someGroupId/someArtifactId/pom.properties")); for await (const fsPath of walk(rootPath)) { if (!fsPath.endsWith(path.sep)) { - const rel = path.relative(rootPath, fsPath).replace(path.sep === "/" ? /\//g : /\\/g, "/") - assert.isOk(zipPaths.includes(rel), `missing ${rel} (${rel}, ${zipPaths.join(", ")})`) + const rel = path.relative(rootPath, fsPath).replace(path.sep === "/" ? /\//g : /\\/g, "/"); + assert.isOk(zipPaths.includes(rel), `missing ${rel} (${rel}, ${zipPaths.join(", ")})`); } } - - }) + }); }); From 466c2d3eb481dc01d888e635b9e1d805c382bbf4 Mon Sep 17 00:00:00 2001 From: Waldemar Reusch Date: Thu, 6 Apr 2023 22:06:42 +0200 Subject: [PATCH 05/10] chore: reenable test cleanup --- test/bin/jar.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/bin/jar.spec.ts b/test/bin/jar.spec.ts index 16d907d0..4499d664 100644 --- a/test/bin/jar.spec.ts +++ b/test/bin/jar.spec.ts @@ -66,9 +66,9 @@ describe("jar", () => { const tmpDirs: string[] = []; - // afterAll(async () => { - // await Promise.all(tmpDirs.map(dir => rm(dir, { force: true, recursive: true }))); - // }); + afterAll(async () => { + await Promise.all(tmpDirs.map(dir => rm(dir, { force: true, recursive: true }))); + }); it("creates jar artifacts without error", async () => { async function* mockFiles(): ZipEntryGenerator { From f8a8ec2e4d5238c77b70c4b40075a4f1245ba10c Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Thu, 6 Apr 2023 22:41:52 +0200 Subject: [PATCH 06/10] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02123009..a2fc9c8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keycloakify", - "version": "7.6.4", + "version": "7.6.5", "description": "Create Keycloak themes using React", "repository": { "type": "git", From b2c7c8660942a23388780b61a47349756f9e5511 Mon Sep 17 00:00:00 2001 From: garronej Date: Fri, 7 Apr 2023 01:38:45 +0200 Subject: [PATCH 07/10] Fix the ftl script --- .../generateFtl/ftl_object_to_js_code_declaring_an_object.ftl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl b/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl index 67c90f19..ddd73476 100644 --- a/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +++ b/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl @@ -1,4 +1,5 @@