Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@Zebradil
Copy link
Member

@Zebradil Zebradil commented Oct 20, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for Kbld tool integration in the rendering pipeline.
    • Enhanced Smart Mode with preview mode and base revision comparison options.
    • Introduced config-in-root configuration option for flexible project setup.
  • Changes

    • Refactored command workflow; all and sync commands replaced by streamlined render command.
    • Improved configuration file discovery and path resolution.
  • Documentation

    • New comprehensive configuration reference guide.
    • Updated examples and documentation to reflect render-centric workflow.
    • Enhanced Smart Mode and plugin documentation.

@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR consolidates the all and sync commands into a unified render workflow by introducing a new RenderCmd function that handles both synchronization and rendering. It adds kbld image-building support through a new embedded tool and render stage, centralizes globe initialization via a getGlobe factory function, refactors path resolution to consistently use RootDir prefixes, introduces a config-in-root configuration option, and expands documentation with a comprehensive configuration guide and updated command examples.

Changes

Cohort / File(s) Summary
Command consolidation and removal
cmd/all.go, cmd/sync.go
Deleted entire command implementations; orchestration logic moved to new RenderCmd function in cmd/render.go
Render command refactoring
cmd/render.go
Introduced new RenderCmd(g *myks.Globe, sync, render bool) error function; added flag synchronization for --sync and --render; replaced fatal-error logging with error returns
Command utility and initialization
cmd/util.go, cmd/root.go
Added getGlobe() factory function and error-handling helpers (okOrFatal, okOrErrLog); refactored command registration to use newRenderCmd(); updated config reading with error handling for config-in-root behavior
Command integration updates
cmd/cleanup.go, cmd/plugin.go, cmd/smart-mode.go
Replaced direct myks.New(".") calls with getGlobe() factory function
Kbld embedding support
cmd/embedded/embedded.go, cmd/embedded/kbld.go
Added kbld case in embedded command routing; new kbld.go file wraps kbld CLI with ConfUI error handling
Entry point simplification
main.go
Simplified command creation to single chained call: cmd.NewMyksCmd(version, commit, date).Execute()
Core globe initialization
internal/myks/globe.go
Introduced initGitData() method; refactored path resolution to prepend RootDir; added YTT library discovery and config dump to initialization flow
Path resolution updates
internal/myks/application.go, internal/myks/bootstrap.go, internal/myks/environment.go
Consistently prepend RootDir to path construction; refactored collectBySubpath to use SplitSeq for level iteration
Git change detection
internal/myks/git.go
Replaced strings.Split with strings.SplitSeq for token iteration
Kbld render integration
internal/myks/render_kbld.go
New file; implements Kbld type with Render() method for image building in render pipeline; includes cache support and configuration
Configuration schema and templates
internal/myks/assets/myks_config.tpl.yaml, internal/myks/assets/data-schema.ytt.yaml
Added config-in-root option; added kbld configuration block with enabled, imagesAnnotation, and cache settings
Test updates
internal/integration/render_test.go
Updated test calls from RunAllCmd() to RenderCmd(myks.New("."), true, true) with error handling
Documentation: README and guides
docs/README.md, docs/configuration.md, docs/smart-mode.md, docs/plugins.md, docs/optimizations.md
Refactored README to emphasize render-centric workflow; added comprehensive configuration reference; updated examples and Smart Mode options; minor fixes and clarity improvements
Example file updates
examples/README.md, examples/*/.gitignore`
Updated relative links; removed .myks/tmp/ ignore entries from .gitignore files
Dependency and build
go.mod, nix/package.nix
Added carvel.dev/kbld and related dependencies; updated vendorHash

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant RenderCmd as RenderCmd Function
    participant Globe
    participant Render as Render Pipeline
    participant Kbld as Kbld Stage

    User->>RenderCmd: RenderCmd(g, sync=true, render=true)
    RenderCmd->>Globe: ValidateRootDir()
    activate Globe
    Globe-->>RenderCmd: ✓
    deactivate Globe
    
    RenderCmd->>Globe: Init(asyncLevel, envAppMap)
    activate Globe
    Globe-->>RenderCmd: ✓
    deactivate Globe
    
    alt sync=true
        RenderCmd->>Globe: Sync(asyncLevel)
        activate Globe
        Globe-->>RenderCmd: ✓
        deactivate Globe
    end
    
    alt render=true
        RenderCmd->>Render: SyncAndRender(asyncLevel)
        activate Render
        Note over Render: Per-app YAML tools
        Render->>Kbld: Render(previousStepFile)
        activate Kbld
        Kbld-->>Render: rendered output
        deactivate Kbld
        Render-->>RenderCmd: ✓
        deactivate Render
    end
    
    alt envAppMap == nil
        RenderCmd->>Globe: CleanupRenderedManifests(false)
        activate Globe
        Globe-->>RenderCmd: ✓
        deactivate Globe
    end
    
    RenderCmd-->>User: error or nil
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The PR involves heterogeneous changes spanning command consolidation, core initialization refactoring, path resolution updates across multiple files, new kbld integration (both embedded and render pipeline), and configuration enhancements. While individual patterns are relatively straightforward, the scope and interconnectedness of changes across command layer, core logic, and configuration schema require careful cross-cutting review of initialization order, error handling, path correctness, and backward compatibility implications.

Possibly related PRs

  • mykso/myks#573: Implements config-in-root configuration option and RootDir handling through viper—directly aligned with this PR's path resolution and configuration centralization changes.
  • mykso/myks#570: Removes cmd/all.go and cmd/sync.go, consolidates behavior into refactored cmd/render.go with new RenderCmd, and updates tests—shares identical core command refactoring logic.

Poem

🐰 Hopping through commands with glee,
All and sync merge into Render's spree,
Kbld builds images in the pipeline's flow,
Root paths unified from head to toe,
Configured in root, we render and go! 🎨✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "kbld" is partially related to the changeset, as it accurately refers to a real feature that was added—the integration of kbld support in cmd/embedded/kbld.go for YAML/image rendering. However, kbld support is not the primary focus of this PR. According to the PR objectives and the scope of changes, the major modifications are the restructuring of CLI commands (removing all and sync commands, refactoring render), adding the config-in-root configuration option, and substantial refactoring of command handling and path resolution. The title does not convey these primary changes, making it difficult for a teammate reviewing commit history to understand the main intent and scope of the PR.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
go.mod (1)

21-21: Migrate from unmaintained gopkg.in/yaml.v3 to actively maintained go.yaml.in/yaml/v3.

The original gopkg.in/yaml.v3 package (github.com/go-yaml/yaml) was archived as unmaintained on Apr 1, 2025. The YAML organization created go.yaml.in/yaml/v3 as the actively maintained drop-in replacement. Your go.mod currently has direct dependency on the unmaintained version while indirect dependencies have migrated to the new path, causing version duplication (v3.0.1 vs v3.0.4) in the dependency graph. Update to go.yaml.in/yaml/v3 to receive ongoing fixes and security updates.

Occurrences at lines 21 and 105 in go.mod.

internal/myks/globe.go (1)

162-186: Swap mismatched log messages (branch vs url)

The warning texts are reversed for branch/URL errors.

-		if gitRepoBranch, err := getGitRepoBranch(g.RootDir); err != nil {
-			log.Warn().Err(err).Msg("Unable to set git repo url")
+		if gitRepoBranch, err := getGitRepoBranch(g.RootDir); err != nil {
+			log.Warn().Err(err).Msg("Unable to set git repo branch")
 		} else {
 			g.GitRepoBranch = gitRepoBranch
 		}
 
-		if gitRepoURL, err := getGitRepoURL(g.RootDir); err != nil {
-			log.Warn().Err(err).Msg("Unable to set git repo branch")
+		if gitRepoURL, err := getGitRepoURL(g.RootDir); err != nil {
+			log.Warn().Err(err).Msg("Unable to set git repo url")
 		} else {
 			g.GitRepoURL = gitRepoURL
 		}
🧹 Nitpick comments (16)
docs/configuration.md (3)

30-37: Clarify precedence between config-in-root and root-dir.

State what wins when both are set (explicit root-dir vs config-in-root). This avoids surprises when users migrate configs.


86-97: Add CLI flag info for root-dir (if it exists).

If there’s a --root-dir flag, list it here for parity with other options; if not supported by design, a one-liner saying “CLI flag not available” helps users.


9-14: Consider documenting .myks.yml (if supported).

If both .myks.yaml and .myks.yml are accepted, list both; if only .yaml is supported, explicitly say so.

docs/smart-mode.md (1)

55-59: Fix markdownlint MD014 for command-only blocks.

Remove “$ ” prompts or include example output. Suggested change: use shell blocks without the prompt.

-```console
-$ myks render --smart-mode.base-revision=main
-$ myks render --smart-mode.base-revision=HEAD~1
-$ myks render --smart-mode.base-revision=v1.2.3
-```
+```shell
+myks render --smart-mode.base-revision=main
+myks render --smart-mode.base-revision=HEAD~1
+myks render --smart-mode.base-revision=v1.2.3
+```
internal/myks/render_kbld.go (2)

54-63: Prefer boolean flag only when true (avoid explicit “=false”).

If kbld accepts a bare --images-annotation boolean flag, append it only when true to reduce ambiguity. Please verify kbld’s CLI semantics first.

-	cmdArgs := []string{
-		"kbld",
-		"--file=" + previousStepFile,
-		"--imgpkg-lock-output=" + lockFilePath,
-		fmt.Sprintf("--images-annotation=%t", config.ImagesAnnotation),
-	}
+	cmdArgs := []string{
+		"kbld",
+		"--file=" + previousStepFile,
+		"--imgpkg-lock-output=" + lockFilePath,
+	}
+	if config.ImagesAnnotation {
+		cmdArgs = append(cmdArgs, "--images-annotation")
+	}

92-95: Consider failing on empty stdout.

Returning an empty string can mask kbld failures upstream. Prefer returning an error so the pipeline stops early.

-	if res.Stdout == "" {
-		log.Warn().Msg(k.app.Msg(k.getStepName(), "Empty kbld output"))
-		return "", nil
-	}
+	if res.Stdout == "" {
+		return "", fmt.Errorf("%s: kbld produced no output", k.getStepName())
+	}
internal/myks/bootstrap.go (1)

137-152: Prefer returning errors from library code instead of log.Fatal

Current log.Fatal calls exit the process from a library function, complicating testing and error handling. Recommend returning errors and letting callers decide.

Proposed refactor (essence):

- func (g *Globe) createDataSchemaFile() string {
+ func (g *Globe) createDataSchemaFile() (string, error) {
   dataSchemaFilePath := filepath.Join(g.RootDir, g.ServiceDirName, g.TempDirName, g.DataSchemaFileName)
   log.Debug().Str("dataSchemaFilePath", dataSchemaFilePath).Msg("Ensuring data schema file exists")
-  if ok, err := isExist(dataSchemaFilePath); err != nil {
-    log.Fatal().Err(err).Msg("Unable to stat data schema file")
+  if ok, err := isExist(dataSchemaFilePath); err != nil {
+    return "", err
   } else if !ok {
-    if err := os.MkdirAll(filepath.Dir(dataSchemaFilePath), 0o750); err != nil {
-      log.Fatal().Err(err).Msg("Unable to create data schema file directory")
-    }
+    if err := os.MkdirAll(filepath.Dir(dataSchemaFilePath), 0o750); err != nil {
+      return "", err
+    }
   } else {
     log.Debug().Msg("Overwriting existing data schema file")
   }
-  if err := os.WriteFile(dataSchemaFilePath, dataSchema, 0o600); err != nil {
-    log.Fatal().Err(err).Msg("Unable to create data schema file")
-  }
-  return dataSchemaFilePath
+  if err := os.WriteFile(dataSchemaFilePath, dataSchema, 0o600); err != nil {
+    return "", err
+  }
+  return dataSchemaFilePath, nil
 }

And update the call site in createBaseFileStructure:

- g.createDataSchemaFile()
+ if _, err := g.createDataSchemaFile(); err != nil {
+   return err
+ }
internal/integration/render_test.go (1)

90-92: LGTM; consider skipping sync to speed tests

Calls to RenderCmd are correct. To reduce CI time, consider render-only when sources are already synced.

- if err := cmd.RenderCmd(myks.New("."), true, true); err != nil {
+ if err := cmd.RenderCmd(myks.New("."), false, true); err != nil {

Also applies to: 122-124

cmd/root.go (1)

31-32: Global globe lifecycle

Pair this with sync.Once in getGlobe() to avoid double init and subtle races during shell-completion vs command execution.

Run the getGlobe change suggested in cmd/util.go and confirm no tests rely on reinitializing globe mid-run.

cmd/render.go (1)

79-85: Exported RenderCmd depends on package global envAppMap

Tight coupling complicates reuse/testing. Consider passing envAppMap as a parameter or deriving it internally from cmd context.

docs/README.md (5)

17-39: Add kbld to the Features list

You’ve added kbld support in this PR; the Features section should reflect it.

Apply:

 - **Plugin system**: [Plugins](/docs/plugins.md) support for extending myks with
   custom tools
+- **Image resolution and lock files**: Resolve image refs to immutable digests and
+  produce lock files with [kbld]; optionally build/push and relocate images

And add a link ref at the bottom section:

 [vendir]: https://carvel.dev/vendir/
 [ytt]: https://carvel.dev/ytt/
+[kbld]: https://carvel.dev/kbld/

157-167: Document flag behavior and mutual exclusivity

Make it explicit that --sync and --render are mutually exclusive and that omitting both runs both stages.

-The `render` command handles both stages and accepts optional flags to control
-behavior:
+The `render` command handles both stages. Flags control behavior:
 
-- By default, it runs both sync and render stages sequentially
-- Use `--sync` to only sync external sources
-- Use `--render` to only render manifests
+- By default, both sync and render stages run sequentially.
+- Use `--sync` to only sync external sources.
+- Use `--render` to only render manifests.
+- Flags `--sync` and `--render` are mutually exclusive.

168-171: Clarify CLI argument grammar with examples

Add concrete examples for envs/apps lists and ALL.

-The `render` command accepts two optional arguments (comma-separated lists or
-`ALL`): environments and applications to process. When no arguments are
-provided, myks will use the [Smart Mode](/docs/smart-mode.md) to detect what to
-process.
+The `render` command accepts two optional arguments (comma-separated lists or `ALL`):
+1) environments, 2) applications. When no arguments are provided, [Smart Mode](/docs/smart-mode.md)
+selects what to process.
+
+Examples:
+```shell
+myks render env-dev,env-stg app-a,app-b
+myks render ALL app-web
+myks render env-prod ALL
+```

176-205: Cross-reference kbld configuration (follow-up doc stub is fine)

Add a short note/link to kbld usage/config, since support was added in this PR.

 ## Configuration
@@
 - `plugin-sources`: Additional directories to search for myks plugins
+
+> [!NOTE]
+> For image resolution/build pipelines, see the kbld integration guide
+> (lock files, image overrides, and relocation). [kbld docs][kbld]

I can draft a minimal docs/kbld.md with examples if helpful.


269-269: Fix markdownlint MD014: drop shell prompts or show output

Remove leading “$ ” prompts in command blocks (or switch to a “shell” fence) to satisfy MD014.

-```console
-$ # Switch to an empty directory
-$ cd $(mktemp -d)
-$ # Initialize a repository
-$ git init
-$ # Make an initial commit
-$ git commit --allow-empty -m "Initial commit"
-$ # Initialize a new myks project
-$ myks init
-$ # Optionally, check the generated files
-$ find
-$ # Sync and render everything
-$ myks render envs --log-level debug
-```
+```shell
+# Switch to an empty directory
+cd "$(mktemp -d)"
+# Initialize a repository
+git init
+# Make an initial commit
+git commit --allow-empty -m "Initial commit"
+# Initialize a new myks project
+myks init
+# Optionally, check the generated files
+find
+# Sync and render everything
+myks render envs --log-level debug
+```
internal/myks/globe.go (1)

141-160: Consider surfacing errors from createDataSchemaFile

If createDataSchemaFile fails, we silently proceed; make it return (string, error) to log or fail early like dumpConfigAsYaml does.

- g.extraYttPaths = append(g.extraYttPaths, g.createDataSchemaFile())
+ if schemaPath, err := g.createDataSchemaFile(); err != nil {
+   log.Warn().Err(err).Msg("Unable to create data schema file")
+ } else {
+   g.extraYttPaths = append(g.extraYttPaths, schemaPath)
+ }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3dff86 and a4b44d8.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (32)
  • cmd/all.go (0 hunks)
  • cmd/cleanup.go (1 hunks)
  • cmd/embedded/embedded.go (2 hunks)
  • cmd/embedded/kbld.go (1 hunks)
  • cmd/plugin.go (1 hunks)
  • cmd/render.go (1 hunks)
  • cmd/root.go (3 hunks)
  • cmd/smart-mode.go (1 hunks)
  • cmd/sync.go (0 hunks)
  • cmd/util.go (1 hunks)
  • docs/README.md (4 hunks)
  • docs/configuration.md (1 hunks)
  • docs/optimizations.md (3 hunks)
  • docs/plugins.md (1 hunks)
  • docs/smart-mode.md (3 hunks)
  • examples/README.md (1 hunks)
  • examples/default/.gitignore (0 hunks)
  • examples/default/envs/.gitignore (0 hunks)
  • examples/integration-tests/.gitignore (0 hunks)
  • examples/simple/.gitignore (0 hunks)
  • go.mod (3 hunks)
  • internal/integration/render_test.go (2 hunks)
  • internal/myks/application.go (2 hunks)
  • internal/myks/assets/data-schema.ytt.yaml (1 hunks)
  • internal/myks/assets/myks_config.tpl.yaml (1 hunks)
  • internal/myks/bootstrap.go (1 hunks)
  • internal/myks/environment.go (3 hunks)
  • internal/myks/git.go (2 hunks)
  • internal/myks/globe.go (3 hunks)
  • internal/myks/render_kbld.go (1 hunks)
  • main.go (1 hunks)
  • nix/package.nix (1 hunks)
💤 Files with no reviewable changes (6)
  • examples/simple/.gitignore
  • examples/default/envs/.gitignore
  • examples/integration-tests/.gitignore
  • examples/default/.gitignore
  • cmd/all.go
  • cmd/sync.go
🧰 Additional context used
🧬 Code graph analysis (10)
docs/optimizations.md (1)
internal/myks/smart_mode.go (1)
  • g (13-41)
cmd/smart-mode.go (1)
internal/myks/smart_mode.go (2)
  • g (13-41)
  • g (60-230)
internal/integration/render_test.go (2)
cmd/render.go (1)
  • RenderCmd (79-102)
internal/myks/globe.go (1)
  • New (131-160)
cmd/render.go (2)
cmd/smart-mode.go (2)
  • AnnotationSmartMode (18-18)
  • AnnotationTrue (19-19)
internal/myks/globe.go (1)
  • Globe (23-108)
main.go (1)
cmd/root.go (1)
  • NewMyksCmd (34-50)
internal/myks/environment.go (1)
internal/myks/render_kbld.go (1)
  • Kbld (12-16)
cmd/util.go (1)
internal/myks/globe.go (2)
  • Globe (23-108)
  • New (131-160)
cmd/root.go (2)
internal/myks/globe.go (1)
  • Globe (23-108)
cmd/embedded/embedded.go (1)
  • EmbeddedCmd (35-44)
internal/myks/render_kbld.go (1)
internal/myks/application.go (1)
  • Application (23-33)
internal/myks/globe.go (1)
internal/myks/environment.go (1)
  • Environment (18-36)
🪛 GitHub Check: lint / lint
internal/myks/globe.go

[failure] 134-134:
Error return value of os.Chdir is not checked (errcheck)

🪛 markdownlint-cli2 (0.18.1)
docs/README.md

269-269: Dollar signs used before commands without showing output

(MD014, commands-show-output)

docs/smart-mode.md

56-56: Dollar signs used before commands without showing output

(MD014, commands-show-output)


57-57: Dollar signs used before commands without showing output

(MD014, commands-show-output)


58-58: Dollar signs used before commands without showing output

(MD014, commands-show-output)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test / test
🔇 Additional comments (31)
examples/README.md (1)

6-7: Clear relative path convention.

The explicit ./ prefix on relative links improves clarity and follows markdown best practices for referencing local files within the repository.

nix/package.nix (1)

13-13: LGTM: Routine vendorHash update.

The vendorHash update is expected given the addition of kbld support and other dependency changes in this PR.

cmd/plugin.go (1)

63-63: LGTM: Centralized globe initialization.

The refactoring to use getGlobe() aligns with the broader pattern of centralizing globe acquisition across command handlers, improving consistency throughout the codebase.

internal/myks/git.go (2)

50-50: LGTM: Iterator-based parsing refactor.

The refactoring from strings.Split to strings.SplitSeq modernizes the code to use iterator patterns while maintaining identical parsing behavior. The logic for handling git diff output remains correct.


76-76: LGTM: Iterator-based parsing refactor.

Consistent with the refactoring in convertDiffToChangedFiles, this change adopts iterator patterns while preserving the correct git status parsing logic.

internal/myks/assets/myks_config.tpl.yaml (1)

5-7: LGTM: Clear documentation for new config-in-root option.

The new config-in-root option is well-documented with clear inline comments explaining its purpose and effect. This aligns with the PR objective to add config-in-root support (ref #573).

internal/myks/application.go (3)

45-45: LGTM: Consistent RootDir-prefixed path construction.

The addition of RootDir prefixing ensures consistent path resolution across the codebase, aligning with the broader refactoring to standardize how paths are constructed relative to the project root.


102-102: LGTM: RootDir prefixing for service paths.

Consistent with the prototype path change, this ensures service paths are correctly resolved relative to RootDir.


106-106: LGTM: RootDir prefixing for vendir cache.

This completes the consistent RootDir prefixing pattern for all path construction in the Application type.

internal/myks/environment.go (3)

44-44: LGTM: RootDir-prefixed environment data path.

Consistent with the path prefixing changes across other files, this ensures the rendered environment data file path is correctly resolved relative to RootDir.


85-85: LGTM: kbld integration.

The addition of Kbld to the YAML templating tools pipeline successfully implements the kbld support mentioned in the PR objectives, completing the rendering workflow with image building capabilities.


342-344: LGTM: Iterator-based path collection refactor.

The refactoring to use strings.SplitSeq and iterator-based loops modernizes the code while maintaining the correct behavior for collecting files by subpath. The path construction logic remains intact.

docs/plugins.md (3)

28-34: LGTM: Enhanced plugin sources documentation.

The additional example directories and clarifying paragraph improve understanding of how plugin sources work, making it clear that multiple directories can be configured beyond the default ./plugins.


38-40: LGTM: Updated execution logic description.

The change from "render and sync logic" to "render logic" correctly reflects the PR's command consolidation where the focus is on the unified render workflow.


43-43: LGTM: Terminology correction.

The capitalization of "YAMLs" improves consistency with technical documentation standards.

cmd/cleanup.go (1)

49-49: LGTM: Centralized globe initialization.

Consistent with the refactoring in cmd/plugin.go, this change adopts the centralized getGlobe() pattern for improved consistency across command handlers.

docs/optimizations.md (1)

25-33: Smart Mode options section reads well and aligns with render workflow.

Good clarity and cross-link to Smart Mode page.

docs/configuration.md (1)

58-69: No changes needed — documentation example is correct.

The myks parser uses go-version, which accepts versions with a leading "v" prefix. The codebase confirms this: myks imports github.com/hashicorp/go-version v1.7.0 and uses gv.NewVersion(minVersion) to parse the configuration value. The documentation example min-version: 'v4.0.0' is valid and will parse correctly.

cmd/embedded/embedded.go (1)

20-21: kbld dispatch addition looks good; confirm entrypoint presence

Wiring kbld via kbldMain matches ytt/vendir pattern. Please confirm kbldMain exists in package embedded and tolerates os.Args = os.Args[1:] semantics.

main.go (1)

24-24: Inline Execute() is fine

Chaining construction + Execute keeps behavior and simplifies flow. No issues.

internal/myks/assets/data-schema.ytt.yaml (1)

121-131: kbld config block added appropriately

Defaults look sane. Ensure CLI/flags and render step honor kbld.enabled and imagesAnnotation/cache behaviors consistently.

cmd/smart-mode.go (2)

29-31: Good: centralizing globe retrieval

Switch to getGlobe() here is consistent with the refactor. No issues.


39-43: <!-- [scratchpad_start]
[task verify_strings_SplitSeq_and_fixes complete]

[observations]

  • strings.SplitSeq IS a real function in Go standard library, added in Go 1.22/1.23
  • According to Go docs: "SplitSeq returns an iterator over all substrings... The iterator yields the same strings that would be returned by Split(s, sep)"
  • Official example from pkg.go.dev: for part := range strings.SplitSeq(s, ",") { fmt.Printf("%q\n", part) } - uses single variable, NOT index
  • SplitSeq returns iter.Seq[string], which yields values (strings), not indices
  • When iterating with for range over an iterator, a single variable receives the value
  • Review comment's claim that for env := range ... yields indexes is INCORRECT - it yields values for iterators
  • Review's suggestion to use for _, env := range strings.Split(...) is also wrong syntax (would be for an actual slice, not iterator)

[critical findings]

  1. The current code for env := range strings.SplitSeq(args[0], ",") is CORRECT syntax
    • SplitSeq returns iter.Seq[string]
    • Iterating with for range on an iterator yields the values directly
    • The variable env receives each string value, not an index
  2. The review's proposed fix for _, env := range strings.Split(args[0], ",") is INCORRECT
    • strings.Split returns []string (slice)
    • For slices, for range yields index, value pairs
    • Using for _, env would work (discarding index, taking value)
    • But the review's syntax shows for _, env := which is unusual phrasing and inconsistent
  3. The issue with strings.SplitSeq NOT being in stdlib is FALSE
  4. The other issues in other files (environment.go, render.go, git.go) using SplitSeq are actually CORRECT

[analysis]

  • Review comment is fundamentally wrong about:
    1. strings.SplitSeq not existing
    2. How iterators work in Go 1.22+ (for range yields values, not indices)
    3. The proposed fix would break the code or introduce subtle differences

[done]
Initial verification complete - review comment contains significant factual errors about Go iterators.
[scratchpad_start] -->

Your review comment contains fundamental factual errors about Go's standard library and how range iteration works with iterators:

strings.SplitSeq is a real Go standard library function (added in Go 1.22–1.23). It returns an iterator over all substrings of s separated by sep, yielding the same strings that would be returned by Split(s, sep), but without constructing the slice.

The current code syntax is correct. The official example from the Go documentation shows: for part := range strings.SplitSeq(s, ",") { fmt.Printf("%q\n", part) } — a single variable receiving the value, not an index. When iterating with for range over an iterator (iter.Seq[string]), the loop variable receives values directly, not indices.

The proposed fix is incorrect. The suggestion to use for _, env := range strings.Split(args[0], ",") changes the semantic—while technically this would work with a slice (where for range yields index, value pairs), it's a different code pattern and removes the iterator efficiency benefit.

The code at lines 39–43 and 52–58 in cmd/smart-mode.go is not breaking. The same pattern is correctly used throughout the codebase (git.go, environment.go, render.go), and all use strings.SplitSeq from the standard library.

The second concern (using myks.NewWithDefaults() instead of getGlobe() at line 56) remains valid and should be addressed to ensure consistent configuration handling.

Likely an incorrect or invalid review comment.

cmd/root.go (2)

45-46: kbld command availability depends on embedded wiring

Ensure the embedded kbld entrypoint is compiled for your release builds; otherwise this command always errors at runtime.

See the kbld wiring script in cmd/embedded/kbld.go comment.


145-157: Verify config-in-root behavior with parent directory configs

The concern is valid: a FIXME comment at globe.go:132 acknowledges os.Chdir() is problematic and suggests implementing relative paths instead. However, the config-in-root feature has no test coverage, and its interaction with shell completion is untested.

Specifically verify:

  • Shell completion (cmd/util.go:39 calls getGlobe()) works correctly when config file is in a parent directory
  • Relative file paths in CLI arguments resolve correctly after CWD changes
  • Dry runs behave as expected in both scenarios: config in current directory vs. parent directory

Consider adding integration tests for this scenario to prevent regressions.

cmd/render.go (1)

22-31: Default behavior: both sync and render when no flags were set

Good UX: mutually exclusive when user specifies, both when unspecified. No change requested.

Confirm help text states “defaults to sync+render” when neither flag is set.

cmd/embedded/kbld.go (1)

15-15: No action required — kbld entrypoint is properly wired and reachable.

The code is working correctly. When myks kbld is invoked, embedded.CheckAndRun() is called immediately in main() (line 20) before Cobra initialization. It matches the switch case for "kbld" and directly invokes kbldMain(), then returns early. The EmbeddedCmd("kbld", ...) stub in cmd/root.go is never reached for direct myks kbld invocations. The routing logic is sound and requires no build tags or additional wiring.

docs/README.md (1)

68-69: LGTM on updated quickstart

Switching the example to “myks render” matches the new unified flow.

internal/myks/globe.go (3)

377-378: LGTM: cache dir now rooted at RootDir

Rooting vendir cache cleanup under RootDir is correct and safer.


471-471: LGTM: search path now RootDir-prefixed

This aligns env discovery with explicit RootDir semantics.


152-156: Remove sensitive content from trace log to prevent credential leakage

The security concern is confirmed. GitRepoURL is populated from git remote get-url origin, which can include embedded credentials in URLs like https://user:[email protected]/repo.git. The log statement at line 433 in internal/myks/globe.go currently logs the full yttData content containing this URL, exposing credentials to logs even at Trace level.

The provided diff is accurate and mandatory. Remove the "content", yttData parameters from the log statement:

-	log.Trace().Str("config file", configFileName).Str("content", yttData).Msg("Dumped config as yaml")
+	log.Trace().Str("config file", configFileName).Msg("Dumped config as yaml")

Likely an incorrect or invalid review comment.

Comment on lines 87 to 101
switch {
case sync && render:
return okOrErrLog(g.SyncAndRender(asyncLevel), "Unable to sync and render applications")
case sync:
return okOrErrLog(g.Sync(asyncLevel), "Unable to sync external sources")
case render:
return okOrErrLog(g.Render(asyncLevel), "Unable to render manifests")
}

// Cleaning up only if all environments and applications were processed
if envAppMap == nil {
return okOrErrLog(g.CleanupRenderedManifests(false), "Unable to cleanup rendered manifests")
}

return nil
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Cleanup is unreachable on normal CLI runs; run cleanup after a full render

Early returns skip post‑render cleanup. With defaults (sync+render), cleanup never runs; stale manifests may persist. Run cleanup after successful render when processing all envs/apps.

- switch {
- case sync && render:
-   return okOrErrLog(g.SyncAndRender(asyncLevel), "Unable to sync and render applications")
- case sync:
-   return okOrErrLog(g.Sync(asyncLevel), "Unable to sync external sources")
- case render:
-   return okOrErrLog(g.Render(asyncLevel), "Unable to render manifests")
- }
-
- // Cleaning up only if all environments and applications were processed
- if envAppMap == nil {
-   return okOrErrLog(g.CleanupRenderedManifests(false), "Unable to cleanup rendered manifests")
- }
-
- return nil
+ // Run actions
+ cleanupAfter := envAppMap == nil && render
+ switch {
+ case sync && render:
+   if err := okOrErrLog(g.SyncAndRender(asyncLevel), "Unable to sync and render applications"); err != nil {
+     return err
+   }
+ case sync:
+   return okOrErrLog(g.Sync(asyncLevel), "Unable to sync external sources")
+ case render:
+   if err := okOrErrLog(g.Render(asyncLevel), "Unable to render manifests"); err != nil {
+     return err
+   }
+ }
+ // Cleaning up only if all environments and applications were processed and a render occurred
+ if cleanupAfter {
+   return okOrErrLog(g.CleanupRenderedManifests(false), "Unable to cleanup rendered manifests")
+ }
+ return nil

🏁 Script executed:

#!/bin/bash
# Ensure no other code path relies on the old fallthrough to trigger cleanup
rg -nP '\bCleanupRenderedManifests\s*\(' -C3

Length of output: 1201


Comment on lines 14 to 19
func getGlobe() *myks.Globe {
if globe == nil {
globe = myks.New(viper.GetString("root-dir"))
}
return globe
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Initialize globe once; avoid races and honor future config changes predictably

Current lazy init isn’t concurrency-safe. Use sync.Once to prevent double-inits under concurrent paths.

 import (
   "path/filepath"
   "strings"
+  "sync"
 
   "github.com/rs/zerolog/log"
   "github.com/spf13/cobra"
   "github.com/spf13/viper"
 )
 
+var globeOnce sync.Once
+
 func getGlobe() *myks.Globe {
-  if globe == nil {
-    globe = myks.New(viper.GetString("root-dir"))
-  }
-  return globe
+  globeOnce.Do(func() {
+    globe = myks.New(viper.GetString("root-dir"))
+  })
+  return globe
 }
📝 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.

Suggested change
func getGlobe() *myks.Globe {
if globe == nil {
globe = myks.New(viper.GetString("root-dir"))
}
return globe
}
import (
"path/filepath"
"strings"
"sync"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var globeOnce sync.Once
func getGlobe() *myks.Globe {
globeOnce.Do(func() {
globe = myks.New(viper.GetString("root-dir"))
})
return globe
}
🤖 Prompt for AI Agents
In cmd/util.go around lines 14 to 19 the lazy initialization of globe is not
concurrency-safe; replace the ad-hoc nil check with sync.Once to guarantee a
single init: add a package-level var globeOnce sync.Once and invoke
globeOnce.Do(func(){ globe = myks.New(viper.GetString("root-dir")) }) inside
getGlobe, then return globe; if you need to allow predictable re-initialization
on config changes, add an explicit ResetGlobe function that sets globe = nil and
globeOnce = sync.Once{} (or use a mutex-based reinit), rather than relying on
concurrent callers to trigger config updates.

Comment on lines 39 to 46
g := getGlobe()
err := g.Init(asyncLevel, map[string][]string{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
// return envs
if len(args) == 0 {
return getEnvNames(tmp), cobra.ShellCompDirectiveNoFileComp
return getEnvNames(g), cobra.ShellCompDirectiveNoFileComp
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Pass nil envAppMap to Init for “all envs/apps” semantics

Empty map can be interpreted differently than nil. Prefer nil to clearly indicate “no filter”.

-  err := g.Init(asyncLevel, map[string][]string{})
+  err := g.Init(asyncLevel, nil)
   if err != nil {
     return nil, cobra.ShellCompDirectiveError
   }
🤖 Prompt for AI Agents
In cmd/util.go around lines 39 to 46, the call g.Init(asyncLevel,
map[string][]string{}) passes an empty map which can be interpreted differently
than a nil filter; change the second argument to nil so Init receives a nil
envAppMap to indicate “no filter / all envs/apps” (i.e. call g.Init(asyncLevel,
nil)); keep the error handling and subsequent logic unchanged.

@@ -1,8 +1,9 @@
module github.com/mykso/myks

go 1.24.6
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Invalid go directive: use major.minor; pin patch via toolchain.

The go directive must be “1.24”, not “1.24.6”. Optionally add a toolchain line to pin the exact patch.

-go 1.24.6
+go 1.24
+
+toolchain go1.24.6
📝 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.

Suggested change
go 1.24.6
go 1.24
toolchain go1.24.6
🤖 Prompt for AI Agents
In go.mod around line 3, the go directive currently specifies a patch version
"1.24.6" which is invalid; change the go directive to the major.minor form
"1.24" and, if you need to pin the exact patch, add a separate toolchain
directive such as "toolchain 1.24.6" on its own line to lock the patch-level
toolchain.

Comment on lines 132 to 136
// FIXME: Do not change working directory here, implement relative paths throughout the codebase instead
if rootDir != "." {
os.Chdir(rootDir)
rootDir = "."
}
Copy link

@coderabbitai coderabbitai bot Oct 20, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Do not mutate process CWD; also fix unchecked os.Chdir error (lint fail)

Changing global CWD is a concurrency and operational hazard; it also triggers errcheck. Prefer keeping RootDir explicit.

Option A (quick fix: pass lint, keep current behavior):

-// FIXME: Do not change working directory here, implement relative paths throughout the codebase instead
-if rootDir != "." {
-	os.Chdir(rootDir)
-	rootDir = "."
-}
+// FIXME: Avoid changing process CWD; see Option B below.
+if rootDir != "." {
+	if err := os.Chdir(rootDir); err != nil {
+		log.Fatal().Err(err).Str("rootDir", rootDir).Msg("Unable to change working directory")
+	}
+	rootDir = "."
+}

Option B (preferred: remove CWD mutation):

-func New(rootDir string) *Globe {
-	// FIXME: Do not change working directory here, implement relative paths throughout the codebase instead
-	if rootDir != "." {
-		os.Chdir(rootDir)
-		rootDir = "."
-	}
+func New(rootDir string) *Globe {
+	cleanRoot := filepath.Clean(rootDir)
 	g := NewWithDefaults()
-	g.RootDir = rootDir
+	g.RootDir = cleanRoot
 	g.environments = make(map[string]*Environment)
 	// ...

🏁 Script executed:

#!/bin/bash
# Scan for other working-directory mutations and suspicious relative I/O.
rg -nP 'os\.Chdir\(|os\.Getwd\('
rg -nP '\bReadFile\("|\bWriteFile\("|\bOpen\("|\bStat\("' -g '!**/vendor/**' -C2
rg -nP 'filepath\.Join\(\s*g\.RootDir' -C1

Length of output: 3757


I need to examine the context around the os.Chdir call and verify whether removing the CWD mutation would break any production code.

Now I need to examine the actual New() function and surrounding code in globe.go to determine if removing the os.Chdir call would break anything:

Now I need to examine the actual New() function to see what happens after the os.Chdir call and determine if removing it would break anything:

[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Examine the New() function in globe.go around line 132-160
sed -n '128,165p' internal/myks/globe.go

Length of output: 1025


I need to verify that the functions called after os.Chdir (like initGitData() and dumpConfigAsYaml()) will properly handle an explicit RootDir path instead of relying on the mutated CWD:

[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Examine initGitData() and dumpConfigAsYaml() to verify they handle g.RootDir properly
echo "=== initGitData() ===" && \
sed -n '/^func (g \*Globe) initGitData/,/^func /p' internal/myks/globe.go | head -20 && \
echo -e "\n=== dumpConfigAsYaml() ===" && \
sed -n '/^func (g \*Globe) dumpConfigAsYaml/,/^func /p' internal/myks/globe.go | head -30

Length of output: 1510


Fix unchecked os.Chdir error (lint violation) and remove process CWD mutation

The unchecked os.Chdir at line 134 violates errcheck linting and creates a concurrency hazard. The codebase is already designed to use explicit paths throughout (all file I/O uses filepath.Join(g.RootDir, ...)), so Option B (removing the CWD mutation) is safe and should be implemented:

func New(rootDir string) *Globe {
-	// FIXME: Do not change working directory here, implement relative paths throughout the codebase instead
-	if rootDir != "." {
-		os.Chdir(rootDir)
-		rootDir = "."
-	}
 	g := NewWithDefaults()
-	g.RootDir = rootDir
+	g.RootDir = filepath.Clean(rootDir)
 	g.environments = make(map[string]*Environment)

Both initGitData() and dumpConfigAsYaml() already pass g.RootDir as explicit path parameters and construct paths via filepath.Join(g.RootDir, ...), so they will continue working correctly with the actual path value instead of relying on CWD mutation.

📝 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.

Suggested change
// FIXME: Do not change working directory here, implement relative paths throughout the codebase instead
if rootDir != "." {
os.Chdir(rootDir)
rootDir = "."
}
func New(rootDir string) *Globe {
g := NewWithDefaults()
g.RootDir = filepath.Clean(rootDir)
g.environments = make(map[string]*Environment)
🧰 Tools
🪛 GitHub Check: lint / lint

[failure] 134-134:
Error return value of os.Chdir is not checked (errcheck)

🤖 Prompt for AI Agents
In internal/myks/globe.go around lines 132-136, the code mutates the process CWD
with an unchecked os.Chdir call (and reassigns rootDir to "."), which violates
errcheck and creates a concurrency hazard; remove the entire if rootDir != "." {
os.Chdir(rootDir); rootDir = "." } block and keep rootDir unchanged, relying on
existing callers (initGitData and dumpConfigAsYaml) that already accept explicit
g.RootDir and build paths with filepath.Join; ensure no other code in this file
depends on the process CWD and adjust any remaining references to use g.RootDir
explicitly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Absolute paths differ in different environments. Those paths are written to some output files that are committed to the repository and shared. Using absolute paths would lead to a constant flow of changes in the output files, depending on where they are generated.

Copy link

Choose a reason for hiding this comment

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

@Zebradil, thank you for that important context about relative paths in committed output files—that's a valid constraint I hadn't fully considered.

However, the unchecked os.Chdir error must be fixed to pass lint (errcheck violation). The minimal fix that preserves your current behavior is Option A from the original comment:

// FIXME: Avoid changing process CWD; refactor to explicit relative paths when possible.
if rootDir != "." {
	if err := os.Chdir(rootDir); err != nil {
		log.Fatal().Err(err).Str("rootDir", rootDir).Msg("Unable to change working directory")
	}
	rootDir = "."
}

This keeps the CWD mutation (so all subsequent relative path operations continue to work as they do now) while satisfying the linter.

Question for future refactoring: Which output files write paths that get committed? If I understand which code writes those paths (e.g., in dumpConfigAsYaml, vendir configs, or rendered manifests), we could potentially refactor to avoid CWD mutation while ensuring paths remain relative to a consistent base. But that would be a larger change outside this PR's scope.

For now, adding the error check is the pragmatic fix. Would you like me to provide that as a committable suggestion?

@Zebradil Zebradil changed the base branch from main to release4 October 20, 2025 16:06
Zebradil and others added 3 commits October 20, 2025 18:09
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Zebradil Zebradil merged commit 6f81acd into release4 Oct 20, 2025
5 of 6 checks passed
@Zebradil Zebradil deleted the kbld branch October 20, 2025 16:19
Zebradil added a commit that referenced this pull request Oct 20, 2025
New major version with a number of improvements.

feat(cmd)!: replace `all`, `sync`, and `render` commands with a single `render` command (#570)

chore: fix typos in documentation and rename embedded.go

refactor(cmd): ensure mutuall exclusivity of sync and render flags via Cobra

feat: add config-in-root option that sets root-dir to the config file location

feat: add kbld support (#626)
@Zebradil Zebradil mentioned this pull request Oct 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants