diff --git a/docs/book/book.toml b/docs/book/book.toml index 494f7e82917..8c3019491e5 100644 --- a/docs/book/book.toml +++ b/docs/book/book.toml @@ -21,4 +21,3 @@ command = "./markerdocs.sh" [context.deploy-preview.environment] environment = { GO_VERSION = "1.23" } - diff --git a/docs/book/src/cronjob-tutorial/testdata/project/cmd/main.go b/docs/book/src/cronjob-tutorial/testdata/project/cmd/main.go index f78383635af..af7761518b0 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/cmd/main.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/cmd/main.go @@ -198,7 +198,7 @@ func main() { os.Exit(1) } - // +kubebuilder:docs-gen:collapse=old stuff + // +kubebuilder:docs-gen:collapse=Remaining code from main.go if err := (&controller.CronJobReconciler{ Client: mgr.GetClient(), @@ -239,5 +239,6 @@ func main() { setupLog.Error(err, "problem running manager") os.Exit(1) } - // +kubebuilder:docs-gen:collapse=old stuff } + +// +kubebuilder:docs-gen:collapse=Remaining code from main.go diff --git a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller.go b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller.go index 3f50231d35a..091bff8a01c 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller.go @@ -68,7 +68,7 @@ type Clock interface { Now() time.Time } -// +kubebuilder:docs-gen:collapse=Clock +// +kubebuilder:docs-gen:collapse=Clock Code Implementation // Definitions to manage status conditions const ( diff --git a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go index 2de2d0cb2fb..a6fbe2d1fe7 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go @@ -208,6 +208,8 @@ var _ = Describe("CronJob controller", func() { }) +// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_controller_test.go + /* After writing all this code, you can run `go test ./...` in your `controllers/` directory again to run your new test! */ diff --git a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/suite_test.go b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/suite_test.go index 6228c33d70d..c74dd849aac 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/suite_test.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/internal/controller/suite_test.go @@ -170,6 +170,8 @@ var _ = AfterSuite(func() { Expect(err).NotTo(HaveOccurred()) }) +// +kubebuilder:docs-gen:collapse=Remaining code from suite_test.go + /* Now that you have your controller running on a test cluster and a client ready to perform operations on your CronJob, we can start writing integration tests! */ diff --git a/docs/book/src/cronjob-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go b/docs/book/src/cronjob-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go index f923176b2e3..a11fb95e8a3 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go @@ -36,7 +36,7 @@ import ( batchv1 "tutorial.kubebuilder.io/project/api/v1" ) -// +kubebuilder:docs-gen:collapse=Go imports +// +kubebuilder:docs-gen:collapse=Imports /* Next, we'll setup a logger for the webhooks. @@ -279,4 +279,4 @@ func validateCronJobName(cronjob *batchv1.CronJob) *field.Error { return nil } -// +kubebuilder:docs-gen:collapse=Validate object name +// +kubebuilder:docs-gen:collapse=validateCronJobName() Code Implementation diff --git a/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go b/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go index 22b11c6ad7b..e92d070bb71 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go @@ -131,7 +131,7 @@ type CronJobStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty"` } -// +kubebuilder:docs-gen:collapse=old stuff +// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_types.go /* Since we'll have more than one version, we'll need to mark a storage version. @@ -183,4 +183,4 @@ func init() { SchemeBuilder.Register(&CronJob{}, &CronJobList{}) } -// +kubebuilder:docs-gen:collapse=old stuff +// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_types.go diff --git a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_conversion.go b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_conversion.go index 139fed85110..d1a7e1461fa 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_conversion.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_conversion.go @@ -90,8 +90,7 @@ func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Active = src.Status.Active dst.Status.LastScheduleTime = src.Status.LastScheduleTime - // +kubebuilder:docs-gen:collapse=rote conversion - + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation return nil } @@ -141,7 +140,6 @@ func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error { dst.Status.Active = src.Status.Active dst.Status.LastScheduleTime = src.Status.LastScheduleTime - // +kubebuilder:docs-gen:collapse=rote conversion - + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation return nil } diff --git a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go index 8906086ea75..ba9ef8f2eac 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go @@ -83,11 +83,10 @@ type CronJobSpec struct { // +optional // +kubebuilder:validation:Minimum=0 FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit,omitempty"` - - // +kubebuilder:docs-gen:collapse=The rest of Spec - } +// +kubebuilder:docs-gen:collapse=CronJobSpec Full Code + /* Next, we'll need to define a type to hold our schedule. Based on our proposed YAML above, it'll have a field for diff --git a/docs/book/src/multiversion-tutorial/testdata/project/cmd/main.go b/docs/book/src/multiversion-tutorial/testdata/project/cmd/main.go index 9fbee250430..4bb34da14fc 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/cmd/main.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/cmd/main.go @@ -204,7 +204,6 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "CronJob") os.Exit(1) } - // +kubebuilder:docs-gen:collapse=existing setup /* Our existing call to SetupWebhookWithManager registers our conversion webhooks with the manager, too. @@ -225,8 +224,7 @@ func main() { } // +kubebuilder:scaffold:builder - /* - */ + // +kubebuilder:docs-gen:collapse=Remaining code from main.go if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") @@ -242,5 +240,8 @@ func main() { setupLog.Error(err, "problem running manager") os.Exit(1) } - // +kubebuilder:docs-gen:collapse=existing setup } + +// +kubebuilder:docs-gen:collapse=Remaining code from main.go + +// +kubebuilder:docs-gen:collapse=Remaining code from main.go diff --git a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller.go b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller.go index 3f50231d35a..091bff8a01c 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller.go @@ -68,7 +68,7 @@ type Clock interface { Now() time.Time } -// +kubebuilder:docs-gen:collapse=Clock +// +kubebuilder:docs-gen:collapse=Clock Code Implementation // Definitions to manage status conditions const ( diff --git a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller_test.go b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller_test.go index 2de2d0cb2fb..a6fbe2d1fe7 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller_test.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/cronjob_controller_test.go @@ -208,6 +208,8 @@ var _ = Describe("CronJob controller", func() { }) +// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_controller_test.go + /* After writing all this code, you can run `go test ./...` in your `controllers/` directory again to run your new test! */ diff --git a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/suite_test.go b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/suite_test.go index 6228c33d70d..c74dd849aac 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/suite_test.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/internal/controller/suite_test.go @@ -170,6 +170,8 @@ var _ = AfterSuite(func() { Expect(err).NotTo(HaveOccurred()) }) +// +kubebuilder:docs-gen:collapse=Remaining code from suite_test.go + /* Now that you have your controller running on a test cluster and a client ready to perform operations on your CronJob, we can start writing integration tests! */ diff --git a/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go b/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go index 7f5224e5581..2eb36e7c9f9 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go @@ -36,7 +36,7 @@ import ( batchv1 "tutorial.kubebuilder.io/project/api/v1" ) -// +kubebuilder:docs-gen:collapse=Go imports +// +kubebuilder:docs-gen:collapse=Imports /* Next, we'll setup a logger for the webhooks. @@ -284,4 +284,4 @@ func validateCronJobName(cronjob *batchv1.CronJob) *field.Error { return nil } -// +kubebuilder:docs-gen:collapse=Validate object name +// +kubebuilder:docs-gen:collapse=validateCronJobName() Code Implementation diff --git a/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v2/cronjob_webhook.go b/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v2/cronjob_webhook.go index 9d6e3d48d71..82668225bc6 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v2/cronjob_webhook.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v2/cronjob_webhook.go @@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +// +kubebuilder:docs-gen:collapse=Apache License package v2 diff --git a/docs/book/theme/css/markers.css b/docs/book/theme/css/markers.css index 44c4e92ebbf..e04fa754d1e 100644 --- a/docs/book/theme/css/markers.css +++ b/docs/book/theme/css/markers.css @@ -212,55 +212,157 @@ input.markers-summarize:checked ~ label.markers-summarize::before { margin-top: 0.125em; } +/* Increase content width to reduce horizontal scrolling */ +.content { + max-width: 95%; + margin-left: auto; + margin-right: auto; +} + +/* Reduce unnecessary padding */ +.content main { + padding-left: 1.5em; + padding-right: 1.5em; +} + +/* Ensure code blocks use available width */ +.content pre { + overflow-x: auto; + max-width: 100%; + padding-left: 0.5em; /* Reduce left padding to save space */ +} + +/* Reduce code indentation to use more horizontal space */ +.content pre > code { + display: block; + padding-left: 0; /* Remove extra left padding from code */ +} + +/* Remove excessive leading whitespace from heavily indented code */ +.hljs { + padding-left: 0.5em !important; + tab-size: 2; /* Make tabs smaller */ +} + +/* Also reduce padding in literate code blocks */ +.literate pre { + padding-left: 0.5em; +} + +details.collapse-code pre { + padding-left: 0.5em; +} + /* details elements (not markers) */ +details.collapse-code { + /* Softer, less prominent styling - more like an aside */ + margin: 0.5em 0; + border: none; + border-radius: 4px; + padding: 0; + background: var(--quote-bg); +} + +/* Completely hide low-value collapsed sections (license text, imports) */ +details.collapse-hide { + display: none; +} + details.collapse-code > summary { width: 100%; cursor: pointer; display: flex; - box-sizing: border-box; /* why isn't this the default? :-/ */ + box-sizing: border-box; + /* Softer styling - no strong background, subtle appearance */ + background: transparent; + border: none; + font-weight: 400; + font-style: italic; + color: var(--fg); + opacity: 0.85; + transition: opacity 0.2s ease; + padding: 0.25em 0.5em; +} + +details.collapse-code > summary:hover { + /* Subtle hover effect */ + opacity: 1; } details.collapse-code > summary::after { - content: "\25c0"; + content: "(click to expand) ▸"; float: right; - font-size: 0.875em; - color: var(--inline-code-color); - opacity: 0.8; + font-size: 0.85em; + color: var(--fg); + opacity: 0.6; + padding: 0 0.5em; } details.collapse-code[open] > summary::after { - content: "\25bc"; + content: "(click to collapse) ▾"; +} + +details.collapse-code[open] { + /* Very subtle indication when expanded - just slightly darker background */ + background: var(--quote-bg); +} + +details.collapse-code[open] > summary { + /* Keep subtle when open */ + border: none; + margin-bottom: 0.5em; } details.collapse-code > summary pre { flex: 1; - box-sizing: border-box; /* why isn't this the default? :-/ */ + box-sizing: border-box; margin: inherit; padding: 0.25em 0.5em; + background: transparent; + font-style: italic; + font-weight: 400; } details.collapse-code > summary pre span::after { - content: " (hidden)"; - font-size: 80%; + content: ""; } details.collapse-code[open] > summary pre span::after { content: ""; } -details.collapse-code > summary pre span::before { - content: "// "; +details.collapse-code > summary pre span.collapse-summary::before { + /* No icon - keep it clean and soft */ + content: ""; +} + +details.collapse-code[open] > summary pre span.collapse-summary::before { + content: ""; +} + +/* Style the collapse summary to not look like code */ +details.collapse-code > summary pre span.collapse-summary { + font-family: var(--font-family); + color: var(--fg); + font-style: italic; + font-weight: 400; +} + +/* Add padding to content inside collapsed sections */ +details.collapse-code[open] > :not(summary) { + padding: 0 0.75em 0.5em 0.75em; } /* make summary into code a bit nicer looking */ -details.collapse-code[open] > summary + pre { - margin-top: 0; +details.collapse-code[open] > summary + * { + margin-top: 0.75em; } /* get rid of the ugly blue box that makes the summary->code look bad */ details.collapse-code summary:focus { - outline: none; - font-weight: bold; /* keep something around for tab users */ + outline: 2px solid var(--links); + outline-offset: -2px; + font-weight: 500; /* keep something around for tab users */ } /* don't show the default expando */ @@ -271,6 +373,51 @@ details.collapse-code > summary::-webkit-details-marker { display: none; } +/* Copy button styling */ +pre .buttons { + opacity: 0; + transition: opacity 0.2s ease; +} + +pre:hover .buttons { + opacity: 1; +} + +.copy-button { + background: var(--sidebar-bg) !important; + border: 1px solid var(--sidebar-fg) !important; + color: var(--sidebar-fg) !important; + padding: 4px 8px !important; + cursor: pointer !important; + border-radius: 3px !important; + font-size: 12px !important; + transition: background-color 0.2s ease, transform 0.1s ease; +} + +.copy-button:hover { + background: var(--theme-hover) !important; + transform: scale(1.05); +} + +.copy-button:active { + transform: scale(0.95); +} + +/* Improve code block spacing and appearance */ +.content pre { + padding-top: 2em; /* Make room for copy button */ +} + +.literate pre { + margin-bottom: 0.5em; +} + +/* Better code block overflow handling */ +.content pre code { + overflow-x: auto; + display: block; +} + /* diagrams */ @@ -365,13 +512,13 @@ cite.literate-source > a::before { color: var(--fg); } -/* hide the annoying "copy to clipboard" buttons */ -.literate pre > .buttons { - display: none; -} - /* add a bit of extra padding for readability */ .literate pre code { padding-top: 0.75em; padding-bottom: 0.75em; } + +/* match master: hide copy button inside literate blocks */ +.literate pre > .buttons { + display: none; +} diff --git a/docs/book/utils/litgo/literate.go b/docs/book/utils/litgo/literate.go index 538af1e016a..5f07be8562d 100644 --- a/docs/book/utils/litgo/literate.go +++ b/docs/book/utils/litgo/literate.go @@ -242,10 +242,12 @@ func (l Literate) extractContents(contents []byte, pathInfo filePathInfo) (strin for _, pair := range pairs { if pair.collapse != "" { - // NB(directxman12): we add the hljs class to "cheat" and get the - // right background with theming, since hljs doesn't use CSS - // variables. - out.WriteString("
")
+			collapseClass := "collapse-code"
+			// Hide low-value sections entirely (licenses, imports, etc)
+			if strings.EqualFold(pair.collapse, "Apache License") || strings.EqualFold(pair.collapse, "Imports") {
+				collapseClass = "collapse-code collapse-hide"
+			}
+			out.WriteString("
")
 			out.WriteString(pair.collapse)
 			out.WriteString("
") } diff --git a/hack/docs/internal/cronjob-tutorial/controller_implementation.go b/hack/docs/internal/cronjob-tutorial/controller_implementation.go index 0c8c2c7230d..c7cd00c8f19 100644 --- a/hack/docs/internal/cronjob-tutorial/controller_implementation.go +++ b/hack/docs/internal/cronjob-tutorial/controller_implementation.go @@ -65,7 +65,7 @@ type Clock interface { Now() time.Time } -// +kubebuilder:docs-gen:collapse=Clock +// +kubebuilder:docs-gen:collapse=Clock Code Implementation // Definitions to manage status conditions const ( diff --git a/hack/docs/internal/cronjob-tutorial/generate_cronjob.go b/hack/docs/internal/cronjob-tutorial/generate_cronjob.go index a15bca243b8..070b82e22e9 100644 --- a/hack/docs/internal/cronjob-tutorial/generate_cronjob.go +++ b/hack/docs/internal/cronjob-tutorial/generate_cronjob.go @@ -358,7 +358,7 @@ CronJob controller's`+" `"+`SetupWithManager`+"`"+` method. os.Exit(1) }`, ` - // +kubebuilder:docs-gen:collapse=old stuff`) + // +kubebuilder:docs-gen:collapse=Remaining code from main.go`) hackutils.CheckError("fixing main.go", err) err = pluginutil.InsertCode( @@ -372,8 +372,9 @@ CronJob controller's`+" `"+`SetupWithManager`+"`"+` method. filepath.Join(sp.ctx.Dir, "cmd/main.go"), `setupLog.Error(err, "problem running manager") os.Exit(1) - }`, ` - // +kubebuilder:docs-gen:collapse=old stuff`) + } +}`, ` +// +kubebuilder:docs-gen:collapse=Remaining code from main.go`) hackutils.CheckError("fixing main.go", err) } diff --git a/hack/docs/internal/cronjob-tutorial/webhook_implementation.go b/hack/docs/internal/cronjob-tutorial/webhook_implementation.go index 79875195891..031c0202f72 100644 --- a/hack/docs/internal/cronjob-tutorial/webhook_implementation.go +++ b/hack/docs/internal/cronjob-tutorial/webhook_implementation.go @@ -19,7 +19,7 @@ package cronjob const webhookIntro = `batchv1 "tutorial.kubebuilder.io/project/api/v1" ) -// +kubebuilder:docs-gen:collapse=Go imports +// +kubebuilder:docs-gen:collapse=Imports /* Next, we'll setup a logger for the webhooks. @@ -178,7 +178,7 @@ func validateCronJobName(cronjob *batchv1.CronJob) *field.Error { return nil } -// +kubebuilder:docs-gen:collapse=Validate object name` +// +kubebuilder:docs-gen:collapse=validateCronJobName() Code Implementation` const fragmentForDefaultFields = ` // Default values for various CronJob fields diff --git a/hack/docs/internal/cronjob-tutorial/writing_tests_controller.go b/hack/docs/internal/cronjob-tutorial/writing_tests_controller.go index 3e8721a7fb8..f4cf2e4ab7b 100644 --- a/hack/docs/internal/cronjob-tutorial/writing_tests_controller.go +++ b/hack/docs/internal/cronjob-tutorial/writing_tests_controller.go @@ -226,6 +226,7 @@ var _ = Describe("CronJob controller", func() { }) }) +// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_controller_test.go /* After writing all this code, you can run` + " `" + `go test ./...` + "`" + ` in your` + " `" + `controllers/` + "`" + ` directory again to run your new test! diff --git a/hack/docs/internal/cronjob-tutorial/writing_tests_env.go b/hack/docs/internal/cronjob-tutorial/writing_tests_env.go index 44cfb0c0cb0..91c8d931f80 100644 --- a/hack/docs/internal/cronjob-tutorial/writing_tests_env.go +++ b/hack/docs/internal/cronjob-tutorial/writing_tests_env.go @@ -120,6 +120,7 @@ var _ = AfterSuite(func() { err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) }) +// +kubebuilder:docs-gen:collapse=Remaining code from suite_test.go /* Now that you have your controller running on a test cluster and a client ready to perform operations on your CronJob, we can start writing integration tests! diff --git a/hack/docs/internal/multiversion-tutorial/cronjob_v1.go b/hack/docs/internal/multiversion-tutorial/cronjob_v1.go index 409f72f6c0d..6da3928ba75 100644 --- a/hack/docs/internal/multiversion-tutorial/cronjob_v1.go +++ b/hack/docs/internal/multiversion-tutorial/cronjob_v1.go @@ -60,7 +60,7 @@ const statusDesignComment = `/* serialization, as mentioned above. */` -const boilerplateReplacement = `// +kubebuilder:docs-gen:collapse=old stuff +const boilerplateReplacement = `// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_types.go /* Since we'll have more than one version, we'll need to mark a storage version. diff --git a/hack/docs/internal/multiversion-tutorial/cronjob_v2.go b/hack/docs/internal/multiversion-tutorial/cronjob_v2.go index 03c6cd2d4bc..84f09cabb77 100644 --- a/hack/docs/internal/multiversion-tutorial/cronjob_v2.go +++ b/hack/docs/internal/multiversion-tutorial/cronjob_v2.go @@ -64,11 +64,10 @@ const cronjobSpecMore = `// startingDeadlineSeconds defines in seconds for start // +optional // +kubebuilder:validation:Minimum=0 FailedJobsHistoryLimit *int32 ` + "`json:\"failedJobsHistoryLimit,omitempty\"`" + ` - - // +kubebuilder:docs-gen:collapse=The rest of Spec - } +// +kubebuilder:docs-gen:collapse=CronJobSpec Full Code + /* Next, we'll need to define a type to hold our schedule. Based on our proposed YAML above, it'll have a field for diff --git a/hack/docs/internal/multiversion-tutorial/generate_multiversion.go b/hack/docs/internal/multiversion-tutorial/generate_multiversion.go index ef9834db0d9..33b4d0f7eb5 100644 --- a/hack/docs/internal/multiversion-tutorial/generate_multiversion.go +++ b/hack/docs/internal/multiversion-tutorial/generate_multiversion.go @@ -387,6 +387,194 @@ Most of the conversion is straightforward copying, except for converting our cha // ConvertTo converts this CronJob (v2) to the Hub version (v1).`) hackutils.CheckError("replace covert info at hub v2", err) + + err = pluginutil.ReplaceInFile(path, + `// ConvertTo converts this CronJob (v2) to the Hub version (v1). +func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*batchv1.CronJob) + log.Printf("ConvertTo: Converting CronJob from Spoke version v2 to Hub version v1;"+ + "source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name) + + sched := src.Spec.Schedule + scheduleParts := []string{"*", "*", "*", "*", "*"} + if sched.Minute != nil { + scheduleParts[0] = string(*sched.Minute) + } + if sched.Hour != nil { + scheduleParts[1] = string(*sched.Hour) + } + if sched.DayOfMonth != nil { + scheduleParts[2] = string(*sched.DayOfMonth) + } + if sched.Month != nil { + scheduleParts[3] = string(*sched.Month) + } + if sched.DayOfWeek != nil { + scheduleParts[4] = string(*sched.DayOfWeek) + } + dst.Spec.Schedule = strings.Join(scheduleParts, " ") + + /* + The rest of the conversion is pretty rote. + */ + // ObjectMeta + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.StartingDeadlineSeconds = src.Spec.StartingDeadlineSeconds + dst.Spec.ConcurrencyPolicy = batchv1.ConcurrencyPolicy(src.Spec.ConcurrencyPolicy) + dst.Spec.Suspend = src.Spec.Suspend + dst.Spec.JobTemplate = src.Spec.JobTemplate + dst.Spec.SuccessfulJobsHistoryLimit = src.Spec.SuccessfulJobsHistoryLimit + dst.Spec.FailedJobsHistoryLimit = src.Spec.FailedJobsHistoryLimit + + // Status + dst.Status.Active = src.Status.Active + dst.Status.LastScheduleTime = src.Status.LastScheduleTime + + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation + + return nil +}`, + `// ConvertTo converts this CronJob (v2) to the Hub version (v1). +func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*batchv1.CronJob) + log.Printf("ConvertTo: Converting CronJob from Spoke version v2 to Hub version v1;"+ + "source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name) + + sched := src.Spec.Schedule + scheduleParts := []string{"*", "*", "*", "*", "*"} + if sched.Minute != nil { + scheduleParts[0] = string(*sched.Minute) + } + if sched.Hour != nil { + scheduleParts[1] = string(*sched.Hour) + } + if sched.DayOfMonth != nil { + scheduleParts[2] = string(*sched.DayOfMonth) + } + if sched.Month != nil { + scheduleParts[3] = string(*sched.Month) + } + if sched.DayOfWeek != nil { + scheduleParts[4] = string(*sched.DayOfWeek) + } + dst.Spec.Schedule = strings.Join(scheduleParts, " ") + + /* + The rest of the conversion is pretty rote. + */ + // ObjectMeta + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.StartingDeadlineSeconds = src.Spec.StartingDeadlineSeconds + dst.Spec.ConcurrencyPolicy = batchv1.ConcurrencyPolicy(src.Spec.ConcurrencyPolicy) + dst.Spec.Suspend = src.Spec.Suspend + dst.Spec.JobTemplate = src.Spec.JobTemplate + dst.Spec.SuccessfulJobsHistoryLimit = src.Spec.SuccessfulJobsHistoryLimit + dst.Spec.FailedJobsHistoryLimit = src.Spec.FailedJobsHistoryLimit + + // Status + dst.Status.Active = src.Status.Active + dst.Status.LastScheduleTime = src.Status.LastScheduleTime + + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation + return nil +}`) + hackutils.CheckError("fix ConvertTo collapse marker placement at hub v2", err) + + err = pluginutil.ReplaceInFile(path, + `// ConvertFrom converts the Hub version (v1) to this CronJob (v2). +func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*batchv1.CronJob) + log.Printf("ConvertFrom: Converting CronJob from Hub version v1 to Spoke version v2;"+ + "source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name) + + schedParts := strings.Split(src.Spec.Schedule, " ") + if len(schedParts) != 5 { + return fmt.Errorf("invalid schedule: not a standard 5-field schedule") + } + partIfNeeded := func(raw string) *CronField { + if raw == "*" { + return nil + } + part := CronField(raw) + return &part + } + dst.Spec.Schedule.Minute = partIfNeeded(schedParts[0]) + dst.Spec.Schedule.Hour = partIfNeeded(schedParts[1]) + dst.Spec.Schedule.DayOfMonth = partIfNeeded(schedParts[2]) + dst.Spec.Schedule.Month = partIfNeeded(schedParts[3]) + dst.Spec.Schedule.DayOfWeek = partIfNeeded(schedParts[4]) + + /* + The rest of the conversion is pretty rote. + */ + // ObjectMeta + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.StartingDeadlineSeconds = src.Spec.StartingDeadlineSeconds + dst.Spec.ConcurrencyPolicy = ConcurrencyPolicy(src.Spec.ConcurrencyPolicy) + dst.Spec.Suspend = src.Spec.Suspend + dst.Spec.JobTemplate = src.Spec.JobTemplate + dst.Spec.SuccessfulJobsHistoryLimit = src.Spec.SuccessfulJobsHistoryLimit + dst.Spec.FailedJobsHistoryLimit = src.Spec.FailedJobsHistoryLimit + + // Status + dst.Status.Active = src.Status.Active + dst.Status.LastScheduleTime = src.Status.LastScheduleTime + + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation + + return nil +}`, + `// ConvertFrom converts the Hub version (v1) to this CronJob (v2). +func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*batchv1.CronJob) + log.Printf("ConvertFrom: Converting CronJob from Hub version v1 to Spoke version v2;"+ + "source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name) + + schedParts := strings.Split(src.Spec.Schedule, " ") + if len(schedParts) != 5 { + return fmt.Errorf("invalid schedule: not a standard 5-field schedule") + } + partIfNeeded := func(raw string) *CronField { + if raw == "*" { + return nil + } + part := CronField(raw) + return &part + } + dst.Spec.Schedule.Minute = partIfNeeded(schedParts[0]) + dst.Spec.Schedule.Hour = partIfNeeded(schedParts[1]) + dst.Spec.Schedule.DayOfMonth = partIfNeeded(schedParts[2]) + dst.Spec.Schedule.Month = partIfNeeded(schedParts[3]) + dst.Spec.Schedule.DayOfWeek = partIfNeeded(schedParts[4]) + + /* + The rest of the conversion is pretty rote. + */ + // ObjectMeta + dst.ObjectMeta = src.ObjectMeta + + // Spec + dst.Spec.StartingDeadlineSeconds = src.Spec.StartingDeadlineSeconds + dst.Spec.ConcurrencyPolicy = ConcurrencyPolicy(src.Spec.ConcurrencyPolicy) + dst.Spec.Suspend = src.Spec.Suspend + dst.Spec.JobTemplate = src.Spec.JobTemplate + dst.Spec.SuccessfulJobsHistoryLimit = src.Spec.SuccessfulJobsHistoryLimit + dst.Spec.FailedJobsHistoryLimit = src.Spec.FailedJobsHistoryLimit + + // Status + dst.Status.Active = src.Status.Active + dst.Status.LastScheduleTime = src.Status.LastScheduleTime + + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation + return nil +}`) + hackutils.CheckError("fix ConvertFrom collapse marker placement at hub v2", err) } func (sp *Sample) updateAPIV1() { @@ -466,7 +654,7 @@ func (sp *Sample) updateAPIV1() { err = pluginutil.ReplaceInFile( filepath.Join(sp.ctx.Dir, "api/v1/cronjob_types.go"), `// +kubebuilder:docs-gen:collapse=Root Object Definitions`, - `// +kubebuilder:docs-gen:collapse=old stuff`, + `// +kubebuilder:docs-gen:collapse=Remaining code from cronjob_types.go`, ) hackutils.CheckError("replacing docs-gen collapse comment", err) } @@ -474,7 +662,13 @@ func (sp *Sample) updateAPIV1() { func (sp *Sample) updateWebhookV2() { path := "internal/webhook/v2/cronjob_webhook.go" - err := pluginutil.InsertCode( + err := pluginutil.InsertCodeIfNotExist( + filepath.Join(sp.ctx.Dir, path), + "limitations under the License.\n*/", + "\n// +kubebuilder:docs-gen:collapse=Apache License") + hackutils.CheckError("adding Apache License collapse marker to webhook v2", err) + + err = pluginutil.InsertCode( filepath.Join(sp.ctx.Dir, path), `import ( "context" @@ -584,7 +778,7 @@ func (sp *Sample) updateMain() { os.Exit(1) } - // +kubebuilder:docs-gen:collapse=old stuff`, + // +kubebuilder:docs-gen:collapse=Remaining code from main.go`, `if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) @@ -637,20 +831,18 @@ CronJob controller's `+"`SetupWithManager`"+` method. os.Exit(1) }`, ` -// +kubebuilder:docs-gen:collapse=existing setup -`, + `, ) - hackutils.CheckError("insert // +kubebuilder:docs-gen:collapse=existing setup main.go", err) + hackutils.CheckError("insert doc marker existing setup main.go", err) err = pluginutil.InsertCode( filepath.Join(sp.ctx.Dir, path), `// +kubebuilder:scaffold:builder`, ` - /* - */`, + // +kubebuilder:docs-gen:collapse=Remaining code from main.go`, ) - hackutils.CheckError("insert doc marker existing setup main.go", err) + hackutils.CheckError("insert opening collapse marker main.go", err) err = pluginutil.ReplaceInFile( filepath.Join(sp.ctx.Dir, path), @@ -668,12 +860,15 @@ CronJob controller's `+"`SetupWithManager`"+` method. ) hackutils.CheckError("replace webhook setup explanation main.go", err) - err = pluginutil.ReplaceInFile( + err = pluginutil.InsertCode( filepath.Join(sp.ctx.Dir, path), - `// +kubebuilder:docs-gen:collapse=old stuff`, - `// +kubebuilder:docs-gen:collapse=existing setup`, + `setupLog.Error(err, "problem running manager") + os.Exit(1) + } +}`, ` +// +kubebuilder:docs-gen:collapse=Remaining code from main.go`, ) - hackutils.CheckError("replace +kubebuilder:docs-gen:collapse=old stuff main.go", err) + hackutils.CheckError("update main.go with final collapse marker", err) } func (sp *Sample) updateAPIV2() { diff --git a/hack/docs/internal/multiversion-tutorial/hub.go b/hack/docs/internal/multiversion-tutorial/hub.go index 696fd5e095d..dabdf7a12df 100644 --- a/hack/docs/internal/multiversion-tutorial/hub.go +++ b/hack/docs/internal/multiversion-tutorial/hub.go @@ -73,7 +73,7 @@ const hubV2CovertTo = `sched := src.Spec.Schedule dst.Status.Active = src.Status.Active dst.Status.LastScheduleTime = src.Status.LastScheduleTime - // +kubebuilder:docs-gen:collapse=rote conversion` + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation` const hubV2ConvertFromCode = `schedParts := strings.Split(src.Spec.Schedule, " ") if len(schedParts) != 5 { @@ -110,4 +110,4 @@ const hubV2ConvertFromCode = `schedParts := strings.Split(src.Spec.Schedule, " " dst.Status.Active = src.Status.Active dst.Status.LastScheduleTime = src.Status.LastScheduleTime - // +kubebuilder:docs-gen:collapse=rote conversion` + // +kubebuilder:docs-gen:collapse=rest of conversion Code Implementation` diff --git a/testdata/project-v4/internal/controller/sailor_controller.go b/testdata/project-v4/internal/controller/sailor_controller.go index 872039e7874..5f3533eccf8 100644 --- a/testdata/project-v4/internal/controller/sailor_controller.go +++ b/testdata/project-v4/internal/controller/sailor_controller.go @@ -45,7 +45,7 @@ type SailorReconciler struct { // the user. // // For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.3/pkg/reconcile +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.4/pkg/reconcile func (r *SailorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = logf.FromContext(ctx)