Skip to content

feat: template consolidation, extend flow, kubeconfig#122

Merged
frezes merged 59 commits intokubesphere:masterfrom
smartcat999:feat/unified-kubeconfig
Apr 3, 2026
Merged

feat: template consolidation, extend flow, kubeconfig#122
frezes merged 59 commits intokubesphere:masterfrom
smartcat999:feat/unified-kubeconfig

Conversation

@smartcat999
Copy link
Copy Markdown
Contributor

@smartcat999 smartcat999 commented Mar 18, 2026

Closes kubesphere/project#7345

Release note

ksbuilder: merge createapp/createsimple into create --type; add kubeconfig, chartmuseum publish, doctor, extend flow, package dependency update; template consolidation

Summary

Addresses Issue #7345 and P2 items:

  • 1 Merge createapp/createsimple: Replace createapp/createsimple with create --type=app|simple --from=<chart>
  • 2 Optimize create templates: Phase 2—unify extension.yaml for app/simple via generator; Phase 3—consolidate static/README/CHANGELOG/.helmignore; add frontend-only/backend-only types
  • 3 Kubeconfig: Add --kubeconfig persistent flag and unified resolution for publish/unpublish/template
  • 4 Publish to chartmuseum: Add publish --target=chartmuseum with --repo, --username, --password; TLS support via --ca-bundle and --insecure-skip-tls-verify
  • 5 Template debugging: Improve ksbuilder template error hints and examples
  • 6 Package dependency: Default to helm dependency update when extension has dependencies; add --skip-dependency-update
  • P2 doctor: Add ksbuilder doctor to check Go, Helm, kubectl, ksbuilder, kubeconfig
  • P2 extend flow: Auto-detect existing extension in ksbuilder create; offer to add missing frontend/backend via ExtendAddFrontend/ExtendAddBackend

Test Plan

  • go test ./pkg/extension ./pkg/extension/generator ./cmd/...
  • ksbuilder create --type=standard
  • ksbuilder create --type=app --from=./chart.tgz
  • ksbuilder create --type=simple --from=./chart.tgz
  • ksbuilder package <dir>
  • ksbuilder doctor

@kubesphere-prow
Copy link
Copy Markdown

This PR has multiple commits, and the default merge method is: squash.
You can request commits to be merged using the label: tide/merge-method-merge

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubesphere-prow
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: smartcat999
Once this PR has been reviewed and has the lgtm label, please assign redscholar for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubesphere-prow kubesphere-prow Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 18, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the extension creation and management workflow by consolidating template logic, introducing a declarative specification for extensions, and enhancing the 'create' command to support incremental additions of capabilities. It also improves the 'package' and 'publish' commands with new features like ChartMuseum integration and a dedicated 'doctor' command for environment validation, aiming to provide a more robust and user-friendly developer experience.

Highlights

  • Template Consolidation: Unified extension.yaml generation for app/simple modes via a new generator, removing redundant template files and streamlining the creation process (Phase 2 & 3).
  • Extended 'create' Command: The 'create' command now supports adding frontend or backend capabilities to existing extensions, and offers interactive prompts for different extension types (standard, app, simple).
  • Declarative Extension Specification: Introduced a .ksbuilder.yaml file and 'spec' package to define extension configurations declaratively, enabling more structured and testable extension creation.
  • Unified Kubeconfig Handling: Implemented a centralized kubeconfig resolution logic, making kubeconfig a persistent flag across relevant commands and removing individual flags.
  • ChartMuseum Publishing Support: Added functionality to publish packaged extensions directly to a ChartMuseum repository, including authentication and TLS options.
  • New 'doctor' Command: Introduced a 'doctor' command to check the development environment for necessary tools like Go, Helm, kubectl, and kubeconfig connectivity.
  • Improved Packaging: The 'package' command now includes an option to skip Helm dependency updates and uses a new internal packaging function.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major refactoring of the extension creation process, consolidating templates and introducing a declarative spec-based flow. It also adds an 'extend' feature to add capabilities to existing extensions, a 'doctor' command for environment checks, and unified kubeconfig handling. The changes are well-structured and follow the provided design document. I've found a few areas with opportunities for improvement, mainly around error handling and code duplication. Overall, this is a great enhancement to the project.

Comment thread cmd/create.go Outdated
func (o *createOptions) run(c *cobra.Command, _ []string) error {
// Extend mode: if extension.yaml exists in current dir, offer to add capabilities
// Must run before any interactive prompts so users in existing extension dirs get extend options
pwd, _ := os.Getwd()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error returned by os.Getwd() is being ignored. While it's unlikely to fail in most scenarios, it's safer to handle it. If it does fail, pwd will be an empty string, which could lead to unexpected behavior in extension.InferCapabilities("").

Comment thread cmd/create.go Outdated
Comment on lines +218 to +237
case "app":
from := o.from
if from == "" {
fromPrompt := inputPromptContent{
text: "Chart file path (e.g. ./demo-0.1.0.tgz)",
errorMsg: "Chart path can't be empty",
}
from = promptGetInput(fromPrompt)
}
return extension.CreateApp(from)
case "simple":
from := o.from
if from == "" {
fromPrompt := inputPromptContent{
text: "Chart file path (e.g. ./demo-0.1.0.tgz)",
errorMsg: "Chart path can't be empty",
}
from = promptGetInput(fromPrompt)
}
return extension.CreateSimple(from)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for getting the from path is duplicated for the "app" and "simple" cases. This can be consolidated to reduce code duplication and improve maintainability.

case "app", "simple":
		from := o.from
		if from == "" {
			fromPrompt := inputPromptContent{
				text:     "Chart file path (e.g. ./demo-0.1.0.tgz)",
				errorMsg: "Chart path can't be empty",
			}
			from = promptGetInput(fromPrompt)
		}
		if typ == "app" {
			return extension.CreateApp(from)
		}
		return extension.CreateSimple(from)

Comment thread cmd/publish.go
if o.repo == "" {
return fmt.Errorf("--target=chartmuseum requires --repo=<chartmuseum URL>\nHint: e.g. --repo=http://localhost:8080")
}
pwd, _ := os.Getwd()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error from os.Getwd() is ignored. If it fails, pwd will be an empty string, which could cause issues when joining paths later on. It's better to handle this error.

Comment thread pkg/chartmuseum/client.go Outdated
}
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error from io.ReadAll(resp.Body) is ignored. If reading the response body fails when the status code indicates an error, the error message for the failed upload will be less informative as it will contain an empty or partial body. It's better to handle this potential error.

Comment thread pkg/extension/extend.go Outdated

// ExtendAddBackend adds backend capability to an existing frontend-only extension.
// root must contain extension.yaml, values.yaml, charts/frontend.
func ExtendAddBackend(root string) error {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication between ExtendAddBackend and ExtendAddFrontend. Much of the logic for updating extension.yaml, values.yaml, and regenerating the root Makefile is repeated. This could be refactored into smaller, reusable helper functions to improve maintainability. For example, you could have helpers for updating dependencies, updating values, and copying scaffolds.

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Add dependency update before packaging when extension.yaml has dependencies.
When metadata.Dependencies is non-empty, run helm dependency update after
writing Chart.yaml and before LoadDir. Use --skip-dependency-update to skip.

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
- Infer version from charts/<name>/Chart.yaml when dependency lacks version
- Return clear error for remote deps (repository set) without version
- Fixes 'improper constraint' when using extension-samples hello-world

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
…Simple

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
P2-2: Remove namespace, externalDependencies, and init container annotations
example comments from create template.

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Signed-off-by: peng wu <2030047311@qq.com>
…nd-only)

P2-2b: When creating from scratch, prompt for template type.
- Standard: frontend+backend (default)
- Frontend only: frontend subchart only
- Backend only: backend subchart only

New embed dirs: templatesfrontend, templatesbackend

Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
…eadAll error

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
…endAddFrontend

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
…ase only

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
@smartcat999 smartcat999 force-pushed the feat/unified-kubeconfig branch from 2efcad6 to 74a1f96 Compare March 18, 2026 03:14
@smartcat999 smartcat999 changed the title feat: template consolidation (Phase 2 & 3), extend flow, kubeconfig feat: template consolidation, extend flow, kubeconfig Mar 24, 2026
@frezes
Copy link
Copy Markdown
Member

frezes commented Mar 24, 2026

前端集成上,可以将 Hello World 项目作为示例进行集成,这里和 @donniean 讨论确认下,保留 src 及目录架构,补充增加 readme, 和 dev-guide 完整结合起来。

https://github.com/kubesphere/extension-samples/tree/master/extensions-frontend/extensions/hello-world
https://dev-guide.kubesphere.io/extension-dev-guide/zh/quickstart/hello-world-extension/

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
…e pullPolicy in values

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
…ev-guide README, workflow hints

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
@smartcat999 smartcat999 force-pushed the feat/unified-kubeconfig branch from d8e9801 to 6c3d91b Compare March 31, 2026 05:55
- Keep generated path as <ext>/frontend/ with workspace root from extension-samples (yarn.lock, babel, configs, tool configs).
- Per-extension scaffold under frontend/extensions/<name>/ from templates/frontend/extensions/scaffold.
- copyFrontendWorkspace skips scaffold when copying workspace; ExtendAddFrontend uses same materialization.
- SystemJS shell lives in src/console-shell.js; dist/index.js via npm run build:shell and Docker stage.
- Update tests and .gitignore for new paths.

Signed-off-by: peng wu <2030047311@qq.com>
@smartcat999 smartcat999 force-pushed the feat/unified-kubeconfig branch from 6c3d91b to aa1b2e4 Compare March 31, 2026 05:56
Only render the frontend or backend block in generated values.yaml when that capability is enabled, so frontend-only scaffolds no longer carry a backend section. Also stop precreating frontend/configs/extensions and align tests/docs with the generated layout.

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Trim leading newlines from ValuesYAML output so backend-only or frontend-only scaffolds start directly with their section key. Add a regression test to ensure values.yaml never begins with an empty line.

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Generate backend dependency without tags for backend-only extensions, while keeping the existing agent tag for mixed frontend+backend mode. Add regression checks for both cases.

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
Set installationMode to Multicluster only when both frontend and backend are enabled. Backend-only extensions now stay HostOnly, and related generator/create tests are updated accordingly.

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
- Document frontend/ workspace and frontend/extensions/<name>/
- Update frontend chart template list and JSBundle example
- Note values.yaml trimming and installationMode rules
- Fix create success hint path to per-extension README

Signed-off-by: peng wu <2030047311@qq.com>
Made-with: Cursor
@frezes
Copy link
Copy Markdown
Member

frezes commented Apr 3, 2026

/lgtm

@kubesphere-prow kubesphere-prow Bot added the lgtm Indicates that a PR is ready to be merged. label Apr 3, 2026
@kubesphere-prow
Copy link
Copy Markdown

LGTM label has been added.

DetailsGit tree hash: 53adebf2f7a58eae29d3f972a5ab8b9ceda806b0

@frezes frezes merged commit a2ef872 into kubesphere:master Apr 3, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm Indicates that a PR is ready to be merged. release-note size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants