feat: support predefined context and skip postbuild / skip jars#921
feat: support predefined context and skip postbuild / skip jars#921zapkub wants to merge 1 commit intokeycloakify:mainfrom
Conversation
WalkthroughAdds CLI flags to skip JAR generation and post-build steps, updates build flow to honor these flags, introduces a print-build-context command, and enables an environment variable to supply a predefined BuildContext. Includes corresponding logs, conditional Maven checks, and a new exported constant for the env key. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as CLI (main.ts)
participant BuildCmd as command() (keycloakify.ts)
participant Maven as Maven
participant Post as Post-build Script
participant Jar as JAR Builder
User->>CLI: keycloakify build [--skip-jar] [--skip-post-build]
CLI->>BuildCmd: command({buildContext, skipJar, skipPostBuild})
alt skipJar == true
Note over BuildCmd: Maven check bypassed
else
BuildCmd->>Maven: verify/install
Maven-->>BuildCmd: ok/fail
end
alt skipPostBuild == true
Note over BuildCmd: Post-build skipped
else
BuildCmd->>Post: run_post_build_script()
Post-->>BuildCmd: done
end
alt skipJar == true
Note over BuildCmd: JAR build skipped (resources kept)
else
BuildCmd->>Jar: buildJars()
Jar-->>BuildCmd: jar files
BuildCmd->>BuildCmd: remove resources dir
end
BuildCmd-->>CLI: complete
CLI-->>User: exit
sequenceDiagram
autonumber
actor User
participant CLI as CLI (main.ts)
participant Ctx as getBuildContext()
User->>CLI: keycloakify print-build-context --project-dir
CLI->>Ctx: getBuildContext({ projectDirPath })
alt Env var set
Ctx->>Ctx: parse process.env.KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT
else
Ctx->>Ctx: compute context from project
end
Ctx-->>CLI: BuildContext
CLI-->>User: JSON(BuildContext) to stdout
sequenceDiagram
autonumber
participant Caller
participant Ctx as getBuildContext()
Caller->>Ctx: getBuildContext(...)
alt KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT present
Note over Ctx: Short-circuit with env JSON
else
Note over Ctx: Use existing derivation logic
end
Ctx-->>Caller: BuildContext
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/bin/keycloakify/keycloakify.ts (1)
53-63: Fix incorrect Maven install commands in help text.
The suggested package names should be “maven”, not “mvn”.Apply this diff:
- const installationCommand = (() => { + const installationCommand = (() => { switch (os.platform()) { case "darwin": - return "brew install mvn"; + return "brew install maven"; case "win32": - return "choco install mvn"; + return "choco install maven"; case "linux": default: - return "sudo apt-get install mvn"; + return "sudo apt-get install maven"; } })();
🧹 Nitpick comments (5)
src/bin/shared/constants.ts (1)
91-91: Name and placement LGTM; add a brief doc for discoverability.
A short JSDoc helps users know how to populate this env var.Apply this diff:
-export const KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT = "KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT"; +/** JSON string from `keycloakify print-build-context` used to bypass subprocesses in getBuildContext */ +export const KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT = "KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT";src/bin/keycloakify/keycloakify.ts (1)
110-117: Make the skip-post-build guidance name the exact env var.
Users see which variable to set without guessing.Apply this diff:
- console.log( - chalk.yellow( - `⚠️ --skip-post-build passed. Skipping the post build script step. (run postbuild manually with RUN_POST_BUILD_SCRIPT env var)` - ) - ); + console.log( + chalk.yellow( + `⚠️ --skip-post-build passed. Skipping the post-build script. ` + + `You can run it manually by setting ${VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RUN_POST_BUILD_SCRIPT}.` + ) + );src/bin/main.ts (3)
71-90: Optional: add short aliases and keep option naming consistentConsider short flags for ergonomics and to align with other options that expose short names (e.g., -p for project). Example: -J for --skip-jar and -B for --skip-post-build. Push both long and short into optionsKeys to keep the unknown-option guard working.
Apply this diff to both options:
.option({ key: "skipJar", - name: (() => { - const name = "skip-jar"; - optionsKeys.push(name); - return name; - })(), + name: (() => { + const long = "skip-jar"; + const short = "J"; + optionsKeys.push(long, short); + return { long, short }; + })(), description: "Skip output JAR file generation.", defaultValue: false }) .option({ key: "skipPostBuild", - name: (() => { - const name = "skip-post-build"; - optionsKeys.push(name); - return name; - })(), + name: (() => { + const long = "skip-post-build"; + const short = "B"; + optionsKeys.push(long, short); + return { long, short }; + })(), description: "Skip post-build steps.", defaultValue: false })
403-403: Nit: polish the help textMinor grammar/style improvement.
- description: "print a build context for non npx build runners. pass the result to KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT env variable", + description: "Print the build context for non-NPX build runners. Pass the result to the KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT environment variable.",
408-410: Ensure JSON-only output and robust serializationIf KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT is set, getBuildContext logs to stdout (“Using predefined build context…”), which will corrupt the JSON stream. Also, buildContext may contain non-serializable/circular values (e.g., getters), risking JSON.stringify failures.
Suggestion: temporarily unset the env var to avoid the extra log and use a safe replacer to drop functions and handle cycles.
- const buildContext = getBuildContext({ projectDirPath }); - console.log(JSON.stringify(buildContext)) + // Avoid stdout noise from env-based short-circuit during printing + const ENV_KEY = "KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT"; + const prev = process.env[ENV_KEY]; + if (prev !== undefined) { + delete process.env[ENV_KEY]; + } + const buildContext = getBuildContext({ projectDirPath }); + if (prev !== undefined) { + process.env[ENV_KEY] = prev; + } + // Safe stringify: drop functions and handle circular refs + const seen = new WeakSet(); + const json = JSON.stringify( + buildContext, + (k, v) => { + if (typeof v === "function") return undefined; + if (typeof v === "object" && v !== null) { + if (seen.has(v)) return undefined; + seen.add(v); + } + return v; + } + ); + console.log(json);If you prefer not to change behavior here, alternatively switch the “Using predefined build context…” log in src/bin/shared/buildContext.ts to stderr (console.error) so it won’t break JSON output.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/bin/keycloakify/keycloakify.ts(3 hunks)src/bin/main.ts(2 hunks)src/bin/shared/buildContext.ts(2 hunks)src/bin/shared/constants.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/bin/shared/buildContext.ts (1)
src/bin/shared/constants.ts (1)
KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT(91-91)
src/bin/keycloakify/keycloakify.ts (3)
src/bin/shared/buildContext.ts (1)
BuildContext(27-78)src/bin/keycloakify/buildJars/buildJars.ts (1)
buildJars(19-68)src/bin/tools/fs.rmSync.ts (1)
rmSync(9-34)
src/bin/main.ts (2)
src/bin/keycloakify/keycloakify.ts (1)
command(13-158)src/bin/shared/buildContext.ts (1)
getBuildContext(133-1073)
🔇 Additional comments (5)
src/bin/shared/buildContext.ts (1)
15-17: Import looks correct and scoped.
No issues with the new constant import.src/bin/keycloakify/keycloakify.ts (2)
21-24: Correct: Maven check bypassed when --skip-jar.
Prevents blocking environments where Maven isn't available.
137-151: Jar skip path is clear and side-effect free.
Leaving resourcesDirPath intact when skipping jar is a sensible default.src/bin/main.ts (2)
67-90: Build flags wired into CLI (skip-jar / skip-post-build): LGTMThe options are correctly added with sane defaults and hooked into the build command.
93-100: Propagation of flags to keycloakify.command: LGTMParameters match the updated signature and will properly bypass Maven and post-build when requested.
| if (process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]){ | ||
| console.log("Using predefined build context from env variable"); | ||
| return JSON.parse(process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]); | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Harden parsing of env-supplied BuildContext (fail fast with actionable errors).
Direct JSON.parse may crash with a vague stack trace and no shape validation. Add try/catch and minimal schema checks so users get clear guidance.
Apply this diff:
- if (process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]){
- console.log("Using predefined build context from env variable");
- return JSON.parse(process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]);
- }
+ if (process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]) {
+ try {
+ const parsed = JSON.parse(process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]!);
+ // Minimal runtime validation to avoid subtle breakages downstream
+ const zMinimal = z.object({
+ packageJsonFilePath: z.string(),
+ keycloakifyBuildDirPath: z.string(),
+ projectDirPath: z.string(),
+ bundler: z.union([z.literal("vite"), z.literal("webpack")]),
+ themeNames: z.array(z.string()).min(1),
+ jarTargets: z
+ .array(
+ z.object({
+ keycloakVersionRange: z.string(),
+ jarFileBasename: z.string()
+ })
+ )
+ .min(1),
+ implementedThemeTypes: z.unknown(),
+ startKeycloakOptions: z.unknown()
+ });
+ zMinimal.parse(parsed);
+ console.log(
+ `Using predefined build context from ${KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT}`
+ );
+ return parsed as BuildContext;
+ } catch (e) {
+ console.error(
+ chalk.red(
+ `Invalid ${KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT}: ${(e as Error).message}. ` +
+ `Tip: run "keycloakify print-build-context" and paste its JSON.`
+ )
+ );
+ process.exit(1);
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]){ | |
| console.log("Using predefined build context from env variable"); | |
| return JSON.parse(process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]); | |
| } | |
| if (process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]) { | |
| try { | |
| const parsed = JSON.parse(process.env[KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT]!); | |
| // Minimal runtime validation to avoid subtle breakages downstream | |
| const zMinimal = z.object({ | |
| packageJsonFilePath: z.string(), | |
| keycloakifyBuildDirPath: z.string(), | |
| projectDirPath: z.string(), | |
| bundler: z.union([z.literal("vite"), z.literal("webpack")]), | |
| themeNames: z.array(z.string()).min(1), | |
| jarTargets: z | |
| .array( | |
| z.object({ | |
| keycloakVersionRange: z.string(), | |
| jarFileBasename: z.string() | |
| }) | |
| ) | |
| .min(1), | |
| implementedThemeTypes: z.unknown(), | |
| startKeycloakOptions: z.unknown() | |
| }); | |
| zMinimal.parse(parsed); | |
| console.log( | |
| `Using predefined build context from ${KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT}` | |
| ); | |
| return parsed as BuildContext; | |
| } catch (e) { | |
| console.error( | |
| chalk.red( | |
| `Invalid ${KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT}: ${(e as Error).message}. ` + | |
| `Tip: run "keycloakify print-build-context" and paste its JSON.` | |
| ) | |
| ); | |
| process.exit(1); | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/bin/shared/buildContext.ts around lines 137 to 141, the code directly
JSON.parses an env var which can throw a vague error and produce an invalid
BuildContext shape; wrap the parse in a try/catch to fail fast with a clear
message if parsing fails, then perform minimal shape validation (e.g., ensure
the result is an object and contains required keys/types used later) and throw a
descriptive Error if validation fails; log or include the env var name and
suggestion to check JSON formatting so callers receive actionable guidance.
There was a problem hiding this comment.
I feel like this runtime type check is unnecessary, but I am happy to fix if you guys need.
There was a problem hiding this comment.
@zapkub Thanks for considering the suggestion! I understand your perspective that the runtime validation might feel like overkill.
The main benefit would be providing clearer error messages to users if they accidentally pass malformed JSON or if the structure doesn't match expectations - instead of getting a cryptic error later in the build process, they'd get an immediate, actionable message pointing them to use keycloakify print-build-context.
Since this feature is designed for users working with non-standard build systems (who are likely more technical), and the JSON is typically generated programmatically via your print-build-context command, I can see the argument that basic JSON.parse() might be sufficient.
Feel free to keep it as-is if you think it's the right balance for your use case. The core functionality works well either way!
|
Hello @zapkub, First, thank you for taking the time to put together this PR, I really appreciate the effort and the thought behind it. 🙏 That said, I don’t think we should move forward with merging this change. The problem this PR addresses (preventing subprocess execution in CI environments) comes from very specific build policies. I completely understand where that comes from, many organizations have strict compliance or reproducibility requirements. The packaging process is already one of the most intricate parts of the project, and every new code path or flag increases maintenance costs and potential edge cases. Given that, I’d prefer to keep the CLI focused and stable, rather than expanding it to accommodate custom CI rules. If you need to adapt Keycloakify to your environment, I’d recommend using So again, thank you for the contribution and for taking the initiative to make Keycloakify work better in your setup. I really appreciate the effort, I just think this particular customization is better handled downstream. 🙏 |
|
@garronej Thank you for your response. We will handle the change in our side and looking forward to contribute the build feature in the future. |
Support build in non
npm, npxbuild system by introduce several options to run build command to avoidchild_processexecution.Mostly the subprocesses are used inside build context factory function. This PR introduce a predefined result of the build context factory function.
KEYCLOAKIFY_PREDEFINED_BUILD_CONTEXT--skip-post-buildoption to skip post build sub process--skip-jaroption to skip mvn packingTest
I have tested with the script below to make sure external sub process won't be
invoked during the build
Summary by CodeRabbit