Implement stary-keycloak-container
This commit is contained in:
parent
e09acedf67
commit
9b27f25f6c
@ -14,7 +14,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
|
|
||||||
const { log } = getLogger({ "isSilent": buildOptions.isSilent });
|
const { log } = getLogger({ "isSilent": buildOptions.isSilent });
|
||||||
|
|
||||||
const { keycloakVersion } = await promptKeycloakVersion();
|
const { keycloakVersion } = await promptKeycloakVersion({
|
||||||
|
"startingFromMajor": undefined
|
||||||
|
});
|
||||||
|
|
||||||
const destDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme");
|
const destDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme");
|
||||||
|
|
||||||
|
@ -28,7 +28,9 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
|||||||
process.exit(-1);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { keycloakVersion } = await promptKeycloakVersion();
|
const { keycloakVersion } = await promptKeycloakVersion({
|
||||||
|
"startingFromMajor": 17
|
||||||
|
});
|
||||||
|
|
||||||
const builtinKeycloakThemeTmpDirPath = pathJoin(buildOptions.cacheDirPath, "initialize-email-theme_tmp");
|
const builtinKeycloakThemeTmpDirPath = pathJoin(buildOptions.cacheDirPath, "initialize-email-theme_tmp");
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { keycloakAccountV1Versions, keycloakThemeAdditionalInfoExtensionVersions
|
|||||||
import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
|
import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
|
||||||
import { buildJar, BuildOptionsLike as BuildOptionsLike_buildJar } from "./buildJar";
|
import { buildJar, BuildOptionsLike as BuildOptionsLike_buildJar } from "./buildJar";
|
||||||
import type { BuildOptions } from "../../shared/buildOptions";
|
import type { BuildOptions } from "../../shared/buildOptions";
|
||||||
import { getJarFileBasename } from "./getJarFileBasename";
|
import { getJarFileBasename } from "../../shared/getJarFileBasename";
|
||||||
import { readMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
import { readMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
|
||||||
import { accountV1ThemeName } from "../../shared/constants";
|
import { accountV1ThemeName } from "../../shared/constants";
|
||||||
|
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
import type { KeycloakAccountV1Version, KeycloakThemeAdditionalInfoExtensionVersion } from "./extensionVersions";
|
import type { KeycloakAccountV1Version, KeycloakThemeAdditionalInfoExtensionVersion } from "./extensionVersions";
|
||||||
import { id } from "tsafe/id";
|
import type { KeycloakVersionRange } from "../../shared/KeycloakVersionRange";
|
||||||
|
|
||||||
export type KeycloakVersionRange = KeycloakVersionRange.WithAccountTheme | KeycloakVersionRange.WithoutAccountTheme;
|
|
||||||
|
|
||||||
export namespace KeycloakVersionRange {
|
|
||||||
export type WithoutAccountTheme = "21-and-below" | "22-and-above";
|
|
||||||
|
|
||||||
export type WithAccountTheme = "21-and-below" | "23" | "24-and-above";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getKeycloakVersionRangeForJar(params: {
|
export function getKeycloakVersionRangeForJar(params: {
|
||||||
doesImplementAccountTheme: boolean;
|
doesImplementAccountTheme: boolean;
|
||||||
@ -18,66 +10,55 @@ export function getKeycloakVersionRangeForJar(params: {
|
|||||||
const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doesImplementAccountTheme } = params;
|
const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doesImplementAccountTheme } = params;
|
||||||
|
|
||||||
if (doesImplementAccountTheme) {
|
if (doesImplementAccountTheme) {
|
||||||
return id<KeycloakVersionRange.WithAccountTheme | undefined>(
|
const keycloakVersionRange = (() => {
|
||||||
(() => {
|
switch (keycloakAccountV1Version) {
|
||||||
switch (keycloakAccountV1Version) {
|
case null:
|
||||||
case null:
|
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
case null:
|
||||||
case null:
|
return "21-and-below" as const;
|
||||||
return "21-and-below" as const;
|
case "1.1.5":
|
||||||
case "1.1.5":
|
return undefined;
|
||||||
return undefined;
|
}
|
||||||
}
|
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
case "0.3":
|
||||||
case "0.3":
|
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
case null:
|
||||||
case null:
|
return undefined;
|
||||||
return undefined;
|
case "1.1.5":
|
||||||
case "1.1.5":
|
return "23" as const;
|
||||||
return "23" as const;
|
}
|
||||||
}
|
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
case "0.4":
|
||||||
case "0.4":
|
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
case null:
|
||||||
case null:
|
return undefined;
|
||||||
return undefined;
|
case "1.1.5":
|
||||||
case "1.1.5":
|
return "24-and-above" as const;
|
||||||
return "24-and-above" as const;
|
}
|
||||||
}
|
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
}
|
||||||
}
|
})();
|
||||||
})()
|
|
||||||
);
|
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme | undefined>>();
|
||||||
|
|
||||||
|
return keycloakVersionRange;
|
||||||
} else {
|
} else {
|
||||||
return id<KeycloakVersionRange.WithoutAccountTheme | undefined>(
|
const keycloakVersionRange = (() => {
|
||||||
(() => {
|
if (keycloakAccountV1Version !== null) {
|
||||||
switch (keycloakAccountV1Version) {
|
return undefined;
|
||||||
case null:
|
}
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
|
||||||
case null:
|
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||||
return "21-and-below";
|
case null:
|
||||||
case "1.1.5":
|
return "21-and-below";
|
||||||
return "22-and-above";
|
case "1.1.5":
|
||||||
}
|
return "22-and-above";
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
}
|
||||||
case "0.3":
|
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
})();
|
||||||
case null:
|
|
||||||
return undefined;
|
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithoutAccountTheme | undefined>>();
|
||||||
case "1.1.5":
|
|
||||||
return undefined;
|
return keycloakVersionRange;
|
||||||
}
|
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
|
||||||
case "0.4":
|
|
||||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
|
||||||
case null:
|
|
||||||
return undefined;
|
|
||||||
case "1.1.5":
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(false);
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import type { BuildOptions } from "../../shared/buildOptions";
|
import type { BuildOptions } from "../../shared/buildOptions";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { generateSrcMainResourcesForMainTheme, type BuildOptionsLike as BuildOptionsLike_generateSrcMainResourcesForMainTheme } from "./generateSrcMainResourcesForMainTheme";
|
import {
|
||||||
|
generateSrcMainResourcesForMainTheme,
|
||||||
|
type BuildOptionsLike as BuildOptionsLike_generateSrcMainResourcesForMainTheme
|
||||||
|
} from "./generateSrcMainResourcesForMainTheme";
|
||||||
import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant";
|
import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant";
|
||||||
|
|
||||||
export type BuildOptionsLike = BuildOptionsLike_generateSrcMainResourcesForMainTheme & {
|
export type BuildOptionsLike = BuildOptionsLike_generateSrcMainResourcesForMainTheme & {
|
||||||
|
7
src/bin/shared/KeycloakVersionRange.ts
Normal file
7
src/bin/shared/KeycloakVersionRange.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export type KeycloakVersionRange = KeycloakVersionRange.WithAccountTheme | KeycloakVersionRange.WithoutAccountTheme;
|
||||||
|
|
||||||
|
export namespace KeycloakVersionRange {
|
||||||
|
export type WithoutAccountTheme = "21-and-below" | "22-and-above";
|
||||||
|
|
||||||
|
export type WithAccountTheme = "21-and-below" | "23" | "24-and-above";
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import type { KeycloakVersionRange } from "./getKeycloakVersionRangeForJar";
|
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
|
||||||
|
|
||||||
export function getJarFileBasename(params: { keycloakVersionRange: KeycloakVersionRange }) {
|
export function getJarFileBasename(params: { keycloakVersionRange: KeycloakVersionRange }) {
|
||||||
const { keycloakVersionRange } = params;
|
const { keycloakVersionRange } = params;
|
@ -4,7 +4,9 @@ import cliSelect from "cli-select";
|
|||||||
import { lastKeycloakVersionWithAccountV1 } from "./constants";
|
import { lastKeycloakVersionWithAccountV1 } from "./constants";
|
||||||
import { SemVer } from "../tools/SemVer";
|
import { SemVer } from "../tools/SemVer";
|
||||||
|
|
||||||
export async function promptKeycloakVersion() {
|
export async function promptKeycloakVersion(params: { startingFromMajor: number | undefined }) {
|
||||||
|
const { startingFromMajor } = params;
|
||||||
|
|
||||||
const { getLatestsSemVersionedTag } = (() => {
|
const { getLatestsSemVersionedTag } = (() => {
|
||||||
const { octokit } = (() => {
|
const { octokit } = (() => {
|
||||||
const githubToken = process.env.GITHUB_TOKEN;
|
const githubToken = process.env.GITHUB_TOKEN;
|
||||||
@ -30,6 +32,10 @@ export async function promptKeycloakVersion() {
|
|||||||
"repo": "keycloak"
|
"repo": "keycloak"
|
||||||
})
|
})
|
||||||
).forEach(semVersionedTag => {
|
).forEach(semVersionedTag => {
|
||||||
|
if (startingFromMajor !== undefined && semVersionedTag.version.major < startingFromMajor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentSemVersionedTag = semVersionedTagByMajor.get(semVersionedTag.version.major);
|
const currentSemVersionedTag = semVersionedTagByMajor.get(semVersionedTag.version.major);
|
||||||
|
|
||||||
if (currentSemVersionedTag !== undefined && SemVer.compare(semVersionedTag.version, currentSemVersionedTag.version) === -1) {
|
if (currentSemVersionedTag !== undefined && SemVer.compare(semVersionedTag.version, currentSemVersionedTag.version) === -1) {
|
||||||
|
@ -1,10 +1,141 @@
|
|||||||
import { readBuildOptions } from "./shared/buildOptions";
|
import { readBuildOptions } from "./shared/buildOptions";
|
||||||
import type { CliCommandOptions } from "./main";
|
import type { CliCommandOptions } from "./main";
|
||||||
|
import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
|
||||||
|
import { readMetaInfKeycloakThemes } from "./shared/metaInfKeycloakThemes";
|
||||||
|
import { accountV1ThemeName } from "./shared/constants";
|
||||||
|
import { SemVer } from "./tools/SemVer";
|
||||||
|
import type { KeycloakVersionRange } from "./shared/KeycloakVersionRange";
|
||||||
|
import { getJarFileBasename } from "./shared/getJarFileBasename";
|
||||||
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { join as pathJoin, posix as pathPosix } from "path";
|
||||||
|
import * as child_process from "child_process";
|
||||||
|
|
||||||
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
||||||
const { cliCommandOptions } = params;
|
const { cliCommandOptions } = params;
|
||||||
|
|
||||||
const buildOptions = readBuildOptions({ cliCommandOptions });
|
const buildOptions = readBuildOptions({ cliCommandOptions });
|
||||||
|
|
||||||
console.log("TODO", buildOptions);
|
const metaInfKeycloakThemes = readMetaInfKeycloakThemes({
|
||||||
|
"keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath
|
||||||
|
});
|
||||||
|
|
||||||
|
const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(({ name }) => name === accountV1ThemeName);
|
||||||
|
|
||||||
|
const { keycloakVersion, keycloakMajorNumber } = await (async function getKeycloakMajor(): Promise<{
|
||||||
|
keycloakVersion: string;
|
||||||
|
keycloakMajorNumber: number;
|
||||||
|
}> {
|
||||||
|
const { keycloakVersion } = await promptKeycloakVersion({
|
||||||
|
"startingFromMajor": 17
|
||||||
|
});
|
||||||
|
|
||||||
|
const keycloakMajorNumber = SemVer.parse(keycloakVersion).major;
|
||||||
|
|
||||||
|
if (doesImplementAccountTheme && keycloakMajorNumber === 22) {
|
||||||
|
console.log([
|
||||||
|
"Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22",
|
||||||
|
"Please select any other Keycloak version"
|
||||||
|
]);
|
||||||
|
return getKeycloakMajor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { keycloakVersion, keycloakMajorNumber };
|
||||||
|
})();
|
||||||
|
|
||||||
|
const keycloakVersionRange: KeycloakVersionRange = (() => {
|
||||||
|
if (doesImplementAccountTheme) {
|
||||||
|
const keycloakVersionRange = (() => {
|
||||||
|
if (keycloakMajorNumber <= 21) {
|
||||||
|
return "21-and-below" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(keycloakMajorNumber !== 22);
|
||||||
|
|
||||||
|
if (keycloakMajorNumber === 23) {
|
||||||
|
return "23" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "24-and-above" as const;
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme>>();
|
||||||
|
|
||||||
|
return keycloakVersionRange;
|
||||||
|
} else {
|
||||||
|
const keycloakVersionRange = (() => {
|
||||||
|
if (keycloakMajorNumber <= 21) {
|
||||||
|
return "21-and-below" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "22-and-above" as const;
|
||||||
|
})();
|
||||||
|
|
||||||
|
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithoutAccountTheme>>();
|
||||||
|
|
||||||
|
return keycloakVersionRange;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange });
|
||||||
|
|
||||||
|
const mountTargets = buildOptions.themeNames
|
||||||
|
.map(themeName => {
|
||||||
|
const themeEntry = metaInfKeycloakThemes.themes.find(({ name }) => name === themeName);
|
||||||
|
|
||||||
|
assert(themeEntry !== undefined);
|
||||||
|
|
||||||
|
return themeEntry.types
|
||||||
|
.map(themeType => {
|
||||||
|
const localPathDirname = pathJoin(
|
||||||
|
buildOptions.keycloakifyBuildDirPath,
|
||||||
|
"src",
|
||||||
|
"main",
|
||||||
|
"resources",
|
||||||
|
"theme",
|
||||||
|
themeName,
|
||||||
|
themeType
|
||||||
|
);
|
||||||
|
|
||||||
|
return fs
|
||||||
|
.readdirSync(localPathDirname)
|
||||||
|
.filter(fileOrDirectoryBasename => !fileOrDirectoryBasename.endsWith(".properties"))
|
||||||
|
.map(fileOrDirectoryBasename => ({
|
||||||
|
"localPath": pathJoin(localPathDirname, fileOrDirectoryBasename),
|
||||||
|
"containerPath": pathPosix.join("/", "opt", "keycloak", "themes", themeName, themeType, fileOrDirectoryBasename)
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
const containerName = "keycloak-keycloakify";
|
||||||
|
|
||||||
|
try {
|
||||||
|
child_process.execSync(`docker rm ${containerName}`, { "stdio": "ignore" });
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
const child = child_process.spawn(
|
||||||
|
"docker",
|
||||||
|
[
|
||||||
|
"run",
|
||||||
|
...["-p", "8080:8080"],
|
||||||
|
...["--name", containerName],
|
||||||
|
...["-e", "KEYCLOAK_ADMIN=admin"],
|
||||||
|
...["-e", "KEYCLOAK_ADMIN_PASSWORD=admin"],
|
||||||
|
...["-v", `"${pathJoin(buildOptions.keycloakifyBuildDirPath, jarFileBasename)}":"/opt/keycloak/providers/keycloak-theme.jar"`],
|
||||||
|
...(keycloakMajorNumber <= 20 ? ["-e", "JAVA_OPTS=-Dkeycloak.profile=preview"] : []),
|
||||||
|
...mountTargets.map(({ localPath, containerPath }) => ["-v", `"${localPath}":"${containerPath}":rw`]).flat(),
|
||||||
|
...["-it", `quay.io/keycloak/keycloak:${keycloakVersion}`],
|
||||||
|
"start-dev",
|
||||||
|
...(21 <= keycloakMajorNumber && keycloakMajorNumber < 24 ? ["--features=declarative-user-profile"] : [])
|
||||||
|
],
|
||||||
|
{
|
||||||
|
"cwd": buildOptions.keycloakifyBuildDirPath
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
child.stdout.on("data", data => console.log(data.toString("utf8")));
|
||||||
|
|
||||||
|
child.stderr.on("data", data => console.error(data.toString("utf8")));
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string
|
|||||||
const cwd = pathResolve(pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")]));
|
const cwd = pathResolve(pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")]));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
child_process.execSync("npm config get", { cwd, "stdio": ["pipe", "pipe", "pipe"] });
|
child_process.execSync("npm config get", { cwd, "stdio": "ignore" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (String(error).includes("ENOWORKSPACES")) {
|
if (String(error).includes("ENOWORKSPACES")) {
|
||||||
assert(cwd !== pathSep, "NPM workspace not found");
|
assert(cwd !== pathSep, "NPM workspace not found");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user