Skip to content

Conversation

@nerdeveloper
Copy link
Contributor

Summary

  • Adds documentation on creating custom markers for unsupported file extensions
  • Shows how to use Kubebuilder as a library for external plugins
  • Includes examples for Rust, Java, Python, and template files

Related

Test Plan

  • Documentation builds correctly
  • Code examples tested and compile without errors
  • Added to SUMMARY.md table of contents

@k8s-ci-robot k8s-ci-robot added the do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. label Sep 22, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Sep 22, 2025
@k8s-ci-robot
Copy link
Contributor

Hi @nerdeveloper. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

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.

@nerdeveloper nerdeveloper force-pushed the docs/custom-markers-issue-4829 branch from ddb8cdb to 161acff Compare September 22, 2025 21:56
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. label Sep 22, 2025
- You're building an **external plugin** for a language not natively supported by Kubebuilder
- You want to scaffold files with custom extensions (`.rs`, `.java`, `.tpl`, `.py`, etc.)
- Your file extensions aren't (and shouldn't be) part of the core `commentsByExt` map
- You need to maintain scaffolding markers in non-Go files
Copy link
Member

Choose a reason for hiding this comment

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

I think the documentation could be How to create Custom Markers.
For those who use Kubebuilder as a library, it would be possible to create their own custom markers, regardless of whether it is for an extension valid or not for Golang projects.

So, it would not only be valid for external references

builder.WriteString(":")
}
return builder.String()
}
Copy link
Member

Choose a reason for hiding this comment

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

Could you let me know if you tested this example?
Can it work without any change in the code at this moment?
Is the code covered with tests to ensure that this example would be possible?

}
```

## Complete Example: Rust Plugin with Custom Markers
Copy link
Member

Choose a reason for hiding this comment

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

Do we need all those examples?
Could we not have only 1 example?
How could we simplify the doc and its maintainability?
Just to share what is required

Comment on lines 295 to 307
## Best Practices

1. **Use Clear Prefixes**: Choose a unique prefix for your plugin to avoid conflicts (e.g., `+rust:scaffold:`, `+java:scaffold:`)

2. **Handle Comments Correctly**: Different languages have different comment syntax. Make sure to map the correct comment style for each file extension.

3. **Error Handling**: Always validate file extensions and return clear error messages when unsupported files are encountered.

4. **Maintain Compatibility**: When possible, follow the same patterns as Kubebuilder's core marker system to maintain consistency.

5. **Document Your Markers**: Clearly document what markers your plugin supports and where they should be placed.

6. **Testing**: Test your marker implementation with various file types and edge cases.
Copy link
Member

@camilamacedo86 camilamacedo86 Sep 24, 2025

Choose a reason for hiding this comment

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

Best Practices is something subjective, I think it's better to avoid this term.

}
```

## Conclusion
Copy link
Member

Choose a reason for hiding this comment

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

Could you please review the other documentation we have?
We do not use a conclusion. We should always follow the same layout and standards.

@nerdeveloper
Copy link
Contributor Author

Hi @camilamacedo86,

Thank you for the review feedback! I've updated the documentation to address your comments:

✅ Changed title to "Creating Custom Markers" (broader scope, not just for unsupported extensions)
✅ Simplified to only ONE example (Rust) instead of multiple examples
✅ Removed "Best Practices" section (subjective term)
✅ Removed "Conclusion" section (to match other docs)
✅ Made the documentation more concise and maintainable

Regarding testing: I performed minimal testing of the marker generation logic by creating a standalone Go program that tests the core marker creation code. The test confirms:

  • The code compiles without errors
  • Markers are generated with correct comment syntax for different file types (e.g., // +rust:scaffold:imports for Rust, # +python:scaffold:functions for Python)
  • The marker format is correct

However, I have NOT tested the complete integration with external plugins end-to-end (the full example with templates and plugin integration).

Question: What would you prefer for this documentation?

  1. Keep the current example as a pattern/reference (with a note that it's not fully integration-tested)
  2. Simplify further to only show the minimal testable code (just the marker creation)
  3. Add a working example to an external test repository and link to it

Please let me know your preference, and I'll update accordingly!

Shows how to use Kubebuilder as a library to create custom marker support
for external plugins with non-Go file extensions like .rs, .java, .py
@nerdeveloper nerdeveloper force-pushed the docs/custom-markers-issue-4829 branch from 161acff to 51faf4e Compare September 27, 2025 10:39
Comment on lines 160 to 168
## Key Considerations

1. **Unique Prefixes**: Choose a unique prefix for your plugin to avoid conflicts (e.g., `+rust:scaffold:`, `+java:scaffold:`)

2. **Comment Syntax**: Different languages have different comment syntax. Ensure you map the correct comment style for each file extension

3. **Error Handling**: Validate file extensions and return clear error messages for unsupported files

4. **Testing**: Test your marker implementation with various scenarios to ensure reliability
Copy link
Member

Choose a reason for hiding this comment

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

I think all is great !!!
Well done 👍 Good job but wdyt about we remove this part?
I think is best we avoid adding things that are more opinionated and keep it as low verbose as possible.


Here's how to implement custom markers for Rust files (`.rs`). This same pattern can be applied to any file extension.

### Define Your Marker Type
Copy link
Member

Choose a reason for hiding this comment

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

Did you test those examples?
Because when it was raised seems like it was missing externalise something.
Is that working properly?
If so, could you please share in the description the POC / tests made?

- Remove Key Considerations section per reviewer feedback
- Update external plugin example to match current API pattern
- Fix external plugin integration code to use JSON/STDIN communication
- Simplify template example to be more realistic for external plugins
- Merge latest changes from master branch

Addresses feedback from PR review comments
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds comprehensive documentation for creating custom markers in Kubebuilder when working with unsupported file extensions. It demonstrates how to use Kubebuilder as a library for external plugins, enabling support for languages beyond Go (such as Rust, Java, and Python) by implementing custom marker systems.

Key Changes:

  • Adds complete guide for implementing custom markers for non-Go file extensions
  • Provides working code examples for Rust-based external plugins
  • Includes integration examples showing external plugin communication patterns

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
docs/book/src/plugins/extending/custom-markers.md New documentation file explaining custom marker implementation with Rust examples and external plugin integration
docs/book/src/SUMMARY.md Adds table of contents entry for the new custom markers documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 159 to 162
case "flags":
response = handleFlags(pluginRequest)
case "metadata":
response = handleMetadata(pluginRequest)
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

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

The example references handleFlags and handleMetadata functions that are not defined or shown in the documentation. Either provide these function implementations or remove these case statements to avoid confusion for readers trying to follow the example.

Suggested change
case "flags":
response = handleFlags(pluginRequest)
case "metadata":
response = handleMetadata(pluginRequest)

Copilot uses AI. Check for mistakes.

func handleInit(req *external.PluginRequest) external.PluginResponse {
// Create Rust file with custom markers
marker, _ := markers.NewRustMarker("src/main.rs", "imports")
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

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

Error is silently discarded using blank identifier. In documentation examples, it's better to demonstrate proper error handling to avoid teaching bad practices. Consider handling the error or adding a comment explaining why it's safe to ignore in this specific context.

Suggested change
marker, _ := markers.NewRustMarker("src/main.rs", "imports")
marker, err := markers.NewRustMarker("src/main.rs", "imports")
if err != nil {
return external.PluginResponse{
Command: "init",
Error: true,
ErrorMsgs: []string{fmt.Sprintf("failed to create Rust marker: %v", err)},
}
}

Copilot uses AI. Check for mistakes.
@nerdeveloper
Copy link
Contributor Author

nerdeveloper commented Oct 27, 2025

How to Test This Implementation

@camilamacedo86 Here are step-by-step instructions to test the custom marker implementation:

Quick Test

1. Test the core marker functionality:

# Create a test file in any directory
cat > test_markers.go << 'EOF'
package main

import (
	"fmt"
	"path/filepath"
	"strings"
)

const RustPluginPrefix = "+rust:scaffold:"

type RustMarker struct {
	prefix  string
	comment string
	value   string
}

func NewRustMarker(path string, value string) (RustMarker, error) {
	ext := filepath.Ext(path)
	if ext != ".rs" {
		return RustMarker{}, fmt.Errorf("expected .rs file, got %s", ext)
	}
	return RustMarker{
		prefix:  formatPrefix(RustPluginPrefix),
		comment: "//",
		value:   value,
	}, nil
}

func (m RustMarker) String() string {
	return m.comment + " " + m.prefix + m.value
}

func formatPrefix(prefix string) string {
	trimmed := strings.TrimSpace(prefix)
	var builder strings.Builder
	if !strings.HasPrefix(trimmed, "+") {
		builder.WriteString("+")
	}
	builder.WriteString(trimmed)
	if !strings.HasSuffix(trimmed, ":") {
		builder.WriteString(":")
	}
	return builder.String()
}

func main() {
	fmt.Println("Testing marker creation...")
	marker, err := NewRustMarker("src/main.rs", "imports")
	if err != nil {
		fmt.Printf("Error: %v", err)
		return
	}
	fmt.Printf("Generated marker: %s", marker.String())
	
	// Test error case
	_, err = NewRustMarker("main.go", "imports")
	if err != nil {
		fmt.Printf("\nCorrect error for Go file: %v", err)
	}
}
EOF

# Run the test
go run test_markers.go

Expected output:

Testing marker creation...
Generated marker: // +rust:scaffold:imports
Correct error for Go file: expected .rs file, got .go

Verify External Plugin Imports

2. Test that external plugin types are accessible:

cat > test_external.go << 'EOF'
package main

import (
	"fmt"
	"sigs.k8s.io/kubebuilder/v4/pkg/plugin/external"
)

func main() {
	var req external.PluginRequest
	var resp external.PluginResponse
	fmt.Printf("PluginRequest available: %T\n", req)
	fmt.Printf("PluginResponse available: %T\n", resp)
	fmt.Println("External plugin imports working!")
}
EOF

go run test_external.go

Expected output:

PluginRequest available: external.PluginRequest
PluginResponse available: external.PluginResponse
External plugin imports working!

Clean Up

rm test_markers.go test_external.go

- Remove undefined function references (handleFlags, handleMetadata)
- Add proper error handling instead of silently discarding errors
- Keep external plugin example simple and focused on custom markers
- Ensure all code examples are self-contained and functional

Addresses Copilot PR review feedback
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@nerdeveloper
Copy link
Contributor Author

when all is good, i wil squash all of them into one commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add docs: how to create custom markers for unsupported file extensions

3 participants