Skip to content

feat(config): implement commented .stackctl init and profile discovery#18

Open
wax911 wants to merge 2 commits into
chore/1-bootstrap-deno-workspace-cifrom
feat/3-implement-config-init-and-profile-discovery
Open

feat(config): implement commented .stackctl init and profile discovery#18
wax911 wants to merge 2 commits into
chore/1-bootstrap-deno-workspace-cifrom
feat/3-implement-config-init-and-profile-discovery

Conversation

@wax911

@wax911 wax911 commented Jun 29, 2026

Copy link
Copy Markdown
Member

Closes #3

  • 5-layer config merge: defaults -> .stackctl base -> profile overlay -> .stackctl.local -> .stackctl.local.
  • Full validation returning all errors at once
  • Commented template generation via stackctl init
  • --preset minimal/standard, --profile support, --detect for auto-discovery
  • 43 tests for load, merge, validate, and init

- Default config values with sensible defaults
- Deep merge for 5-layer config resolution (defaults -> base -> profile -> local -> local-profile)
- Filesystem discovery (.stackctl, .stackctl.<profile>, .stackctl.local, .stackctl.local.<profile>)
- Post-merge validation returning all errors at once
- Template generation with inline comments, --detect, --preset, --profile, --force, --dry-run
- STACKCTL_PROFILE env var support
- 43 config tests + existing 15 = 58 passing
- CLI init command wired to real implementation

@wax911 wax911 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review notes against #3:

  1. Profile ambiguity/default-profile behavior is not implemented. resolveConfig() only reads --profile/STACKCTL_PROFILE; it does not use project.defaultProfile, and it does not detect multiple .stackctl.* files to prompt interactively or fail in non-interactive mode as required.

  2. stackctl init --detect is too shallow for the local-stack use case. It only scans first-level files in cwd, derives stack names from service names, and does not inspect nested service compose files, x-stack, existing stack files, sibling swarm fragments, SOPS config, example env files, or encrypted env files as required.

  3. --write-gitignore is parsed by the CLI but is not passed into initConfig() or implemented. That path is currently dead.

  4. Profile generation writes the same full base template to .stackctl.<profile>. A profile overlay should be shorter, profile-specific, and include a profile: <name> field or equivalent intent. Copying the full base config increases drift risk and does not match the planned overlay model.

  5. The generated template is not parsed/validated before writing. The issue explicitly requires generated commented config to be reparsed before save so broken templates cannot be emitted.

  6. The template schema does not match the agreed plan. It uses project: "" and stack: whereas the planned shape used structured sections for project, stacks, generation, render, docker, env, secrets, overrides, and commands. Either align the schema or explicitly update the issue/spec before merging.

This needs another pass before it can close #3.

@wax911 wax911 changed the base branch from main to chore/1-bootstrap-deno-workspace-ci June 29, 2026 15:43
- Add defaultProfile fallback when --profile not specified
- Detect multiple .stackctl.* files and fail on ambiguity
- Deepen --detect to scan subdirectories, fragments, SOPS, env files
- Move --write-gitignore into initConfig function
- Generate shorter profile-specific overlays instead of full templates
- Validate generated template before writing
- Expand template schema with secrets, overrides, commands sections

@wax911 wax911 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Follow-up review after the push:

Fixed/improved:

  • --write-gitignore now exists in InitOptions and is passed from the CLI.
  • Generated config is parsed before writing.
  • Profile generation now uses a smaller overlay template with an explicit profile field.
  • defaultProfile/profile fallback logic was added.
  • Profile ambiguity is now detected and reported.

Remaining issues:

  1. The PR is currently not mergeable. Resolve the conflict/base issue before it is considered ready.

  2. Detection is still not aligned with local-stack. It scans only root plus one directory deep. local-stack can contain nested service directories, so this should use configured discovery globs / recursive walk with skip directories.

  3. Detection still confuses stack names and services. The local-stack convention is a top-level compose extension x-stack: <stackName> in each service compose file. The current detection mostly derives names from service names unless it finds service-level x-stack, which is not the same contract.

  4. Existing stacks/*.yml files are scanned but added to fragments; they should be used to infer stack names from filenames.

  5. The config schema still diverges from the earlier agreed shape (project, stack, render) instead of the richer project.name, stacks, generation, docker, overrides, etc. That may be acceptable if the implementation intentionally simplified the schema, but then update the issue/spec/docs so every downstream PR uses the same contract.

This is materially better, but still not ready to close #3 for local-stack compatibility.

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.

feat(config): implement commented .stackctl init and profile discovery

1 participant