Multi target build (checkpoint before futher refactor)

This commit is contained in:
Joseph Garrone 2024-05-12 19:16:59 +02:00
parent d4f5a1fff4
commit 385cb85309
11 changed files with 170 additions and 47 deletions

View File

@ -0,0 +1,15 @@
import { assert, type Equals } from "tsafe/assert";
import { exclude } from "tsafe/exclude";
import type { KeycloakAccountV1Versions, KeycloakThemeAdditionalInfoExtensionVersions } from "./extensionVersions";
export async function buildJar(params: {
jarFileBasename: string;
keycloakAccountV1Version: KeycloakAccountV1Versions;
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersions;
buildOptions: {
keycloakifyBuildDirPath: string;
};
}): Promise<void> {
child_process.execSync("mvn clean install", { "cwd": buildOptions.keycloakifyBuildDirPath });
// TODO: Implement
}

View File

@ -0,0 +1,57 @@
import { assert } from "tsafe/assert";
import { exclude } from "tsafe/exclude";
import { keycloakAccountV1Versions, keycloakThemeAdditionalInfoExtensionVersions } from "./extensionVersions";
import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
import { buildJar } from "./buildJar";
export async function buildJars(params: {
doImplementAccountTheme: boolean;
buildOptions: {
keycloakifyBuildDirPath: string;
};
}): Promise<{ lastJarFileBasename: string }> {
const { doImplementAccountTheme, buildOptions } = params;
let lastJarFileBasename: string | undefined = undefined;
await Promise.all(
keycloakAccountV1Versions
.map(keycloakAccountV1Version =>
keycloakThemeAdditionalInfoExtensionVersions
.map(keycloakThemeAdditionalInfoExtensionVersion => {
const keycloakVersionRange = getKeycloakVersionRangeForJar({
doImplementAccountTheme,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion
});
if (keycloakVersionRange === undefined) {
return undefined;
}
return { keycloakThemeAdditionalInfoExtensionVersion, keycloakVersionRange };
})
.filter(exclude(undefined))
.map(({ keycloakThemeAdditionalInfoExtensionVersion, keycloakVersionRange }) => {
const jarFileBasename = `keycloak-theme-for-kc-${keycloakVersionRange}.jar`;
lastJarFileBasename = jarFileBasename;
return { keycloakThemeAdditionalInfoExtensionVersion, jarFileBasename };
})
.map(({ keycloakThemeAdditionalInfoExtensionVersion, jarFileBasename }) =>
buildJar({
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion,
buildOptions
})
)
)
.flat()
);
assert(lastJarFileBasename !== undefined);
return { lastJarFileBasename };
}

View File

@ -0,0 +1,7 @@
export const keycloakAccountV1Versions = [null, "0.3", "0.4"] as const;
export type KeycloakAccountV1Versions = (typeof keycloakAccountV1Versions)[number];
export const keycloakThemeAdditionalInfoExtensionVersions = [null, "0.1"] as const;
export type KeycloakThemeAdditionalInfoExtensionVersions = (typeof keycloakThemeAdditionalInfoExtensionVersions)[number];

View File

@ -0,0 +1,37 @@
import { assert, type Equals } from "tsafe/assert";
import type { KeycloakAccountV1Versions, KeycloakThemeAdditionalInfoExtensionVersions } from "./extensionVersions";
export function getKeycloakVersionRangeForJar(params: {
doImplementAccountTheme: boolean;
keycloakAccountV1Version: KeycloakAccountV1Versions;
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersions;
}): string | undefined {
const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doImplementAccountTheme } = params;
switch (keycloakAccountV1Version) {
case null:
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return doImplementAccountTheme ? "21-and-below" : "21-and-below";
case "0.1":
return doImplementAccountTheme ? undefined : "22-and-above";
}
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
case "0.3":
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return doImplementAccountTheme ? undefined : undefined;
case "0.1":
return doImplementAccountTheme ? "23" : undefined;
}
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
case "0.4":
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return doImplementAccountTheme ? undefined : undefined;
case "0.1":
return doImplementAccountTheme ? "24-and-above" : undefined;
}
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
}
}

View File

@ -0,0 +1 @@
export * from "./buildJars";

View File

@ -4,7 +4,6 @@ export type UserProvidedBuildOptions = {
extraThemeProperties?: string[]; extraThemeProperties?: string[];
artifactId?: string; artifactId?: string;
groupId?: string; groupId?: string;
doCreateJar?: boolean;
loginThemeResourcesFromKeycloakVersion?: string; loginThemeResourcesFromKeycloakVersion?: string;
reactAppBuildDirPath?: string; reactAppBuildDirPath?: string;
keycloakifyBuildDirPath?: string; keycloakifyBuildDirPath?: string;
@ -15,7 +14,6 @@ export const zUserProvidedBuildOptions = z.object({
"extraThemeProperties": z.array(z.string()).optional(), "extraThemeProperties": z.array(z.string()).optional(),
"artifactId": z.string().optional(), "artifactId": z.string().optional(),
"groupId": z.string().optional(), "groupId": z.string().optional(),
"doCreateJar": z.boolean().optional(),
"loginThemeResourcesFromKeycloakVersion": z.string().optional(), "loginThemeResourcesFromKeycloakVersion": z.string().optional(),
"reactAppBuildDirPath": z.string().optional(), "reactAppBuildDirPath": z.string().optional(),
"keycloakifyBuildDirPath": z.string().optional(), "keycloakifyBuildDirPath": z.string().optional(),

View File

@ -18,7 +18,6 @@ export type BuildOptions = {
extraThemeProperties: string[] | undefined; extraThemeProperties: string[] | undefined;
groupId: string; groupId: string;
artifactId: string; artifactId: string;
doCreateJar: boolean;
loginThemeResourcesFromKeycloakVersion: string; loginThemeResourcesFromKeycloakVersion: string;
reactAppRootDirPath: string; reactAppRootDirPath: string;
reactAppBuildDirPath: string; reactAppBuildDirPath: string;
@ -115,7 +114,6 @@ export function readBuildOptions(params: { processArgv: string[] }): BuildOption
); );
})(), })(),
"artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? userProvidedBuildOptions.artifactId ?? `${themeNames[0]}-keycloak-theme`, "artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? userProvidedBuildOptions.artifactId ?? `${themeNames[0]}-keycloak-theme`,
"doCreateJar": userProvidedBuildOptions.doCreateJar ?? true,
"loginThemeResourcesFromKeycloakVersion": userProvidedBuildOptions.loginThemeResourcesFromKeycloakVersion ?? "24.0.4", "loginThemeResourcesFromKeycloakVersion": userProvidedBuildOptions.loginThemeResourcesFromKeycloakVersion ?? "24.0.4",
reactAppRootDirPath, reactAppRootDirPath,
reactAppBuildDirPath, reactAppBuildDirPath,

View File

@ -17,10 +17,11 @@ export type BuildOptionsLike = {
generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh"; generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
const containerName = "keycloak-testing-container"; const containerName = "keycloak-testing-container";
const keycloakVersion = "24.0.4";
/** Files for being able to run a hot reload keycloak container */ /** Files for being able to run a hot reload keycloak container */
export function generateStartKeycloakTestingContainer(params: { jarFilePath: string; keycloakVersion: string; buildOptions: BuildOptionsLike }) { export function generateStartKeycloakTestingContainer(params: { jarFilePath: string; buildOptions: BuildOptionsLike }) {
const { jarFilePath, keycloakVersion, buildOptions } = params; const { jarFilePath, buildOptions } = params;
const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme"); const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme");
const themeDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, themeRelativeDirPath); const themeDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, themeRelativeDirPath);

View File

@ -31,7 +31,6 @@ export type BuildOptionsLike = {
cacheDirPath: string; cacheDirPath: string;
assetsDirPath: string; assetsDirPath: string;
urlPathname: string | undefined; urlPathname: string | undefined;
themeNames: string[];
npmWorkspaceRootDirPath: string; npmWorkspaceRootDirPath: string;
}; };
@ -43,7 +42,7 @@ export async function generateTheme(params: {
keycloakifySrcDirPath: string; keycloakifySrcDirPath: string;
buildOptions: BuildOptionsLike; buildOptions: BuildOptionsLike;
keycloakifyVersion: string; keycloakifyVersion: string;
}): Promise<void> { }): Promise<{ implementedThemeTypes: Record<ThemeType | "email", boolean> }> {
const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params; const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params;
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => { const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
@ -231,14 +230,12 @@ export async function generateTheme(params: {
const parsedKeycloakThemeJson: { themes: { name: string; types: string[] }[] } = { "themes": [] }; const parsedKeycloakThemeJson: { themes: { name: string; types: string[] }[] } = { "themes": [] };
buildOptions.themeNames.forEach(themeName =>
parsedKeycloakThemeJson.themes.push({ parsedKeycloakThemeJson.themes.push({
"name": themeName, "name": themeName,
"types": Object.entries(implementedThemeTypes) "types": Object.entries(implementedThemeTypes)
.filter(([, isImplemented]) => isImplemented) .filter(([, isImplemented]) => isImplemented)
.map(([themeType]) => themeType) .map(([themeType]) => themeType)
}) });
);
account_specific_extra_work: { account_specific_extra_work: {
if (!implementedThemeTypes.account) { if (!implementedThemeTypes.account) {
@ -269,4 +266,6 @@ export async function generateTheme(params: {
fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(parsedKeycloakThemeJson, null, 2), "utf8")); fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(parsedKeycloakThemeJson, null, 2), "utf8"));
} }
return { implementedThemeTypes };
} }

View File

@ -0,0 +1,12 @@
import type { ThemeType } from "../constants";
export function generateThemeVariations(params: {
themeName: string;
themeVariantName: string;
implementedThemeTypes: Record<ThemeType | "email", boolean>;
buildOptions: {
keycloakifyBuildDirPath: string;
};
}) {
//TODO: Implement
}

View File

@ -10,6 +10,8 @@ import { getThemeSrcDirPath } from "../getThemeSrcDirPath";
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath"; import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
import { readThisNpmProjectVersion } from "../tools/readThisNpmProjectVersion"; import { readThisNpmProjectVersion } from "../tools/readThisNpmProjectVersion";
import { keycloakifyBuildOptionsForPostPostBuildScriptEnvName } from "../constants"; import { keycloakifyBuildOptionsForPostPostBuildScriptEnvName } from "../constants";
import { buildJars } from "./buildJars";
import { generateThemeVariations } from "./generateThemeVariants";
export async function main() { export async function main() {
const buildOptions = readBuildOptions({ const buildOptions = readBuildOptions({
@ -21,14 +23,23 @@ export async function main() {
const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath }); const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath });
for (const themeName of buildOptions.themeNames) { const [themeName, ...themeVariantNames] = buildOptions.themeNames;
await generateTheme({
const { implementedThemeTypes } = await generateTheme({
themeName, themeName,
themeSrcDirPath, themeSrcDirPath,
"keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"), "keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"),
"keycloakifyVersion": readThisNpmProjectVersion(), "keycloakifyVersion": readThisNpmProjectVersion(),
buildOptions buildOptions
}); });
for (const themeVariantName of themeVariantNames) {
generateThemeVariations({
themeName,
themeVariantName,
implementedThemeTypes,
buildOptions
});
} }
{ {
@ -37,16 +48,6 @@ export async function main() {
fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, "pom.xml"), Buffer.from(pomFileCode, "utf8")); fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, "pom.xml"), Buffer.from(pomFileCode, "utf8"));
} }
const containerKeycloakVersion = "24.0.4";
const jarFilePath = pathJoin(buildOptions.keycloakifyBuildDirPath, "target", `${buildOptions.artifactId}-${buildOptions.themeVersion}.jar`);
generateStartKeycloakTestingContainer({
"keycloakVersion": containerKeycloakVersion,
jarFilePath,
buildOptions
});
fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8")); fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8"));
run_post_build_script: { run_post_build_script: {
@ -63,27 +64,24 @@ export async function main() {
}); });
} }
create_jar: { const { lastJarFileBasename } = await buildJars({
if (!buildOptions.doCreateJar) { "doImplementAccountTheme": implementedThemeTypes.account,
break create_jar; buildOptions
} });
child_process.execSync("mvn clean install", { "cwd": buildOptions.keycloakifyBuildDirPath }); generateStartKeycloakTestingContainer({
} "jarFilePath": pathJoin(buildOptions.keycloakifyBuildDirPath, lastJarFileBasename),
buildOptions
});
logger.log( logger.log(
[ [
`✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathJoin(
pathRelative(buildOptions.reactAppRootDirPath, buildOptions.keycloakifyBuildDirPath),
"keycloak-theme-for-kc-*.jar"
)}`,
"", "",
...(!buildOptions.doCreateJar `To test your theme locally you can spin up a Keycloak container image with the theme pre loaded by running:`,
? []
: [
`✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathRelative(
buildOptions.reactAppRootDirPath,
jarFilePath
)} 🚀`
]),
"",
`To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
"", "",
`👉 $ .${pathSep}${pathRelative( `👉 $ .${pathSep}${pathRelative(
buildOptions.reactAppRootDirPath, buildOptions.reactAppRootDirPath,