Skip to content

Commit 5de272c

Browse files
committed
chore: release v0.5.0
- Add debug logging for performance profiling - Add performance warnings for config-based secrets - Add comprehensive configuration documentation - Update CHANGELOG and website docs
1 parent e4c8c88 commit 5de272c

10 files changed

Lines changed: 352 additions & 37 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.5.0] - 2025-10-10
11+
1012
### Added
13+
- **Debug logging** - Added detailed debug logs for performance profiling of stack parsing, esbuild bundling, and secret resolution. Enable with `log_level: debug` in config or `COMET_LOG_LEVEL=debug` environment variable.
14+
- **Configuration documentation** - New comprehensive configuration guide in website docs covering all options, environment variables, and performance considerations.
1115
- **`comet types` command** - Generate TypeScript definitions for IDE support on-demand
1216

1317
### Fixed
1418
- Skip parsing TypeScript definition files (`.d.ts`) to prevent parse errors
1519

1620
### Changed
21+
- **Performance warning for config-based secrets** - Added warning when using `op://` or `sops://` references in `comet.yaml` env section, as these are resolved on every command and can add 3-5 seconds. Documentation now recommends setting frequently-used secrets in shell environment instead.
1722
- TypeScript definitions are now opt-in via `comet types` instead of auto-generated
1823

1924
### Added
20-
- **Config-based environment variables** - Pre-load environment variables from `comet.yaml` before any command runs. Perfect for setting `SOPS_AGE_KEY` and other secrets needed during stack parsing. Supports secret resolution via `op://` and `sops://` prefixes. Shell environment variables take precedence.
25+
- **Config-based environment variables** - Pre-load environment variables from `comet.yaml` before any command runs. Perfect for setting `SOPS_AGE_KEY` and other secrets needed during stack parsing. Supports secret resolution via `op://` and `sops://` prefixes. Shell environment variables take precedence. ⚠️ **Note:** Secret resolution can be slow (3-5s per secret with 1Password CLI); consider setting in shell for frequently-used values.
2126
- **`comet init` command** - Initialize backends and providers without running plan/apply operations. Useful for read-only operations like `comet output` or troubleshooting provider/backend initialization issues.
2227
- **DSL Improvements** - Two core enhancements to reduce boilerplate by ~30%:
2328
- Bulk environment variables: `envs({})` accepts objects to set multiple vars at once
@@ -58,5 +63,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5863
- Support for Terraform and OpenTofu
5964
- CLI commands: plan, apply, destroy, list, output, clean
6065

61-
[Unreleased]: https://github.com/moonwalker/comet/compare/v0.1.0...HEAD
66+
[Unreleased]: https://github.com/moonwalker/comet/compare/v0.5.0...HEAD
67+
[0.5.0]: https://github.com/moonwalker/comet/releases/tag/v0.5.0
6268
[0.1.0]: https://github.com/moonwalker/comet/releases/tag/v0.1.0

Makefile

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
VERSION=v0.4.7
1+
VERSION=v0.5.0
22

3-
# Bump patch version, commit, tag, and release
4-
bump:
5-
@echo "Current version: ${VERSION}"
6-
@NEW_VERSION=v0.4.7
7-
echo "Bumping to $$NEW_VERSION..." && \
8-
sed -i.bak "s/VERSION=v0.4.7
9-
rm -f Makefile.bak && \
10-
git add Makefile && \
11-
git commit -m "chore: bump version to $$NEW_VERSION" && \
12-
git tag -a $$NEW_VERSION -m "Release $$NEW_VERSION" && \
13-
git push && git push origin $$NEW_VERSION && \
14-
echo "✅ Released $$NEW_VERSION - GitHub Action will build and publish"
3+
.PHONY: build
4+
build:
5+
@echo "Building comet..."
6+
go build -o comet
157

16-
# Bump minor version (0.x.0)
17-
bump-minor:
18-
@echo "Current version: ${VERSION}"
19-
@NEW_VERSION=v0.4.7
20-
echo "Bumping to $$NEW_VERSION..." && \
21-
sed -i.bak "s/VERSION=v0.4.7
22-
rm -f Makefile.bak && \
23-
git add Makefile && \
24-
git commit -m "chore: bump version to $$NEW_VERSION" && \
25-
git tag -a $$NEW_VERSION -m "Release $$NEW_VERSION" && \
26-
git push && git push origin $$NEW_VERSION && \
27-
echo "✅ Released $$NEW_VERSION - GitHub Action will build and publish"
8+
.PHONY: release
9+
release:
10+
@echo "Creating release ${VERSION}..."
11+
@echo "Make sure CHANGELOG.md is updated!"
12+
@read -p "Continue? [y/N] " -n 1 -r; \
13+
echo; \
14+
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
15+
git add -A && \
16+
git commit -m "chore: release ${VERSION}" && \
17+
git tag -a ${VERSION} -m "Release ${VERSION}" && \
18+
git push && git push origin ${VERSION} && \
19+
echo "✅ Released ${VERSION} - GitHub Action will build and publish"; \
20+
else \
21+
echo "❌ Release cancelled"; \
22+
fi
23+
24+
.PHONY: website
25+
website:
26+
@echo "Deploying website (triggers on push to main)..."
27+
@echo "Website changes will deploy automatically when pushed to main"

README.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,19 +381,37 @@ Pre-load environment variables before any command runs. Perfect for secrets need
381381
```yaml
382382
# comet.yaml
383383
env:
384-
# Load SOPS AGE key from 1Password (or other secret manager)
385-
SOPS_AGE_KEY: op://ci-cd/sops-age-key/private
386-
387-
# Plain values work too
384+
# Plain values - fast and simple
388385
TF_LOG: DEBUG
389386
AWS_REGION: us-west-2
387+
388+
# Secret references - convenient but SLOW (3-5s per secret on every command)
389+
# SOPS_AGE_KEY: op://ci-cd/sops-age-key/private # ⚠️ Adds ~4s to EVERY command
390390
```
391391

392392
**Features:**
393393
- Supports `op://` (1Password) and `sops://` secret resolution
394394
- Shell environment variables take precedence
395395
- Loaded before stack parsing begins
396396

397+
**⚠️ Performance Warning:**
398+
399+
Secret references (`op://`, `sops://`) are resolved on **EVERY** comet command (plan, apply, list, etc.), which can add 3-5 seconds due to CLI overhead.
400+
401+
**Recommended approach for frequently-used secrets:**
402+
403+
```bash
404+
# Set in your shell (one-time cost)
405+
export SOPS_AGE_KEY=$(op read "op://ci-cd/sops-age-key/private")
406+
407+
# Or add to ~/.bashrc, ~/.zshrc, ~/.config/fish/config.fish, etc.
408+
```
409+
410+
Only use secret references in `comet.yaml` for:
411+
- Secrets that change frequently
412+
- CI/CD environments where shell setup is inconvenient
413+
- Situations where the ~3-5s overhead is acceptable
414+
397415
See [Best Practices](docs/best-practices.md) for more configuration examples.
398416

399417
## Development

cmd/root.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"strings"
7+
"time"
78

89
"github.com/spf13/cobra"
910

@@ -50,19 +51,28 @@ func loadConfigEnv(config *schema.Config) {
5051
for key, value := range config.Env {
5152
// Skip if already set in shell environment (shell wins)
5253
if os.Getenv(key) != "" {
54+
log.Debug("Env var already set, skipping", "key", key)
5355
continue
5456
}
5557

5658
// Resolve secrets if value starts with op:// or sops://
5759
if strings.HasPrefix(value, "op://") || strings.HasPrefix(value, "sops://") {
60+
start := time.Now()
61+
log.Debug("Resolving secret for env var", "key", key, "ref", value)
62+
log.Warn(fmt.Sprintf("Loading secret for %s from config - this runs on EVERY command and may be slow (consider setting in shell instead)", key))
63+
5864
resolved, err := secrets.Get(value)
65+
duration := time.Since(start)
66+
log.Debug("Secret resolution completed", "key", key, "duration", duration)
67+
5968
if err != nil {
6069
log.Error(fmt.Sprintf("failed to resolve env var %s: %v", key, err))
6170
continue
6271
}
6372
os.Setenv(key, resolved)
6473
} else {
6574
// Plain value
75+
log.Debug("Setting env var from config", "key", key)
6676
os.Setenv(key, value)
6777
}
6878
}

comet.yaml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ stacks_dir: stacks
22
work_dir: stacks/_components
33
generate_backend: false
44

5-
# Pre-load environment variables before any command runs
6-
# Perfect for SOPS AGE key which is needed during stack parsing
7-
env:
8-
SOPS_AGE_KEY: op://ci-cd/sops-age-key/private
5+
# Environment variables loaded before every command
6+
# NOTE: Shell environment variables take precedence over these
7+
# WARNING: Using op:// or sops:// references here can be slow (3-5s per secret)
8+
# as they are resolved on EVERY comet command (plan, apply, list, etc.)
9+
# Consider setting frequently-used secrets in your shell instead:
10+
# export SOPS_AGE_KEY=$(op read "op://vault/item/field")
11+
# env:
12+
# EXAMPLE_VAR: "plain-value"
13+
# SLOW_SECRET: "op://vault/item/field" # ⚠️ Adds ~4s to every command!
14+
15+

internal/parser/js/js.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"reflect"
77
"strings"
8+
"time"
89

910
"github.com/dop251/goja"
1011
"github.com/evanw/esbuild/pkg/api"
@@ -36,11 +37,17 @@ func NewInterpreter() (*jsinterpreter, error) {
3637
}
3738

3839
func (vm *jsinterpreter) Parse(path string) (*schema.Stack, error) {
40+
log.Debug("JS Parse started", "path", path)
41+
42+
buildStart := time.Now()
3943
result := api.Build(api.BuildOptions{
4044
EntryPoints: []string{path},
4145
Bundle: true,
4246
Write: false,
4347
})
48+
buildTime := time.Since(buildStart)
49+
log.Debug("esbuild completed", "path", path, "duration", buildTime)
50+
4451
if len(result.Errors) > 0 {
4552
return nil, fmt.Errorf(errBuild, path, result.Errors)
4653
}
@@ -50,6 +57,7 @@ func (vm *jsinterpreter) Parse(path string) (*schema.Stack, error) {
5057

5158
stack := schema.NewStack(path, "js")
5259

60+
setupStart := time.Now()
5361
vm.rt.Set("print", fmt.Println)
5462
vm.rt.Set("env", vm.envProxy())
5563
vm.rt.Set("envs", vm.envsFunc)
@@ -61,9 +69,15 @@ func (vm *jsinterpreter) Parse(path string) (*schema.Stack, error) {
6169
vm.rt.Set("component", vm.registerComponent(stack))
6270
vm.rt.Set("append", vm.registerAppend(stack))
6371
vm.rt.Set("kubeconfig", vm.registerKubeconfig(stack))
72+
setupTime := time.Since(setupStart)
73+
log.Debug("Runtime setup completed", "path", path, "duration", setupTime)
6474

75+
execStart := time.Now()
6576
src := result.OutputFiles[0].Contents
6677
_, err := vm.rt.RunString(string(src))
78+
execTime := time.Since(execStart)
79+
log.Debug("Script execution completed", "path", path, "duration", execTime)
80+
6781
if err != nil {
6882
return nil, err
6983
}
@@ -124,7 +138,13 @@ func (vm *jsinterpreter) envsFunc(args ...goja.Value) any {
124138
}
125139

126140
func (vm *jsinterpreter) secretsFunc(ref string) any {
141+
start := time.Now()
142+
log.Debug("secrets.Get called", "ref", ref)
143+
127144
res, err := secrets.Get(ref)
145+
duration := time.Since(start)
146+
log.Debug("secrets.Get completed", "ref", ref, "duration", duration)
147+
128148
if err != nil {
129149
log.Fatal(err)
130150
}
@@ -144,17 +164,24 @@ func (vm *jsinterpreter) secretsConfigFunc(config map[string]interface{}) {
144164

145165
// secretFunc is a shorthand version of secretsFunc using configured defaults
146166
func (vm *jsinterpreter) secretFunc(path string) any {
167+
start := time.Now()
168+
log.Debug("secret called", "path", path)
169+
147170
// If path already has a provider prefix, use it as-is
148171
if strings.HasPrefix(path, "sops://") || strings.HasPrefix(path, "op://") {
149-
return vm.secretsFunc(path)
172+
result := vm.secretsFunc(path)
173+
log.Debug("secret completed", "path", path, "duration", time.Since(start))
174+
return result
150175
}
151176

152177
// Support dot notation (e.g., "datadog.api_key" -> "datadog/api_key")
153178
path = strings.ReplaceAll(path, ".", "/")
154179

155180
// Construct full reference using defaults
156181
ref := fmt.Sprintf("%s://%s#/%s", vm.secretsDefaultProvider, vm.secretsDefaultPath, path)
157-
return vm.secretsFunc(ref)
182+
result := vm.secretsFunc(ref)
183+
log.Debug("secret completed", "path", path, "duration", time.Since(start))
184+
return result
158185
}
159186

160187
func (vm *jsinterpreter) registerStack(stack *schema.Stack) func(string, map[string]interface{}) goja.Value {

internal/parser/parser.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import (
77
"path/filepath"
88
"slices"
99
"strings"
10+
"time"
1011

1112
"github.com/bmatcuk/doublestar/v4"
1213

14+
"github.com/moonwalker/comet/internal/log"
1315
"github.com/moonwalker/comet/internal/parser/js"
1416
"github.com/moonwalker/comet/internal/schema"
1517
)
@@ -27,6 +29,9 @@ var (
2729
)
2830

2931
func LoadStacks(dir string) (*schema.Stacks, error) {
32+
start := time.Now()
33+
log.Debug("LoadStacks started", "dir", dir)
34+
3035
stacks := &schema.Stacks{}
3136

3237
err := doublestar.GlobWalk(os.DirFS(dir), globpattern, func(p string, d fs.DirEntry) error {
@@ -36,16 +41,24 @@ func LoadStacks(dir string) (*schema.Stacks, error) {
3641
}
3742

3843
path := filepath.Join(dir, p)
44+
fileStart := time.Now()
45+
log.Debug("Parsing stack file", "path", p)
3946

4047
parser, err := getParser(path)
4148
if err != nil {
4249
return err
4350
}
51+
parserTime := time.Since(fileStart)
52+
log.Debug("getParser completed", "path", p, "duration", parserTime)
4453

54+
parseStart := time.Now()
4555
stack, err := parser.Parse(path)
4656
if err != nil {
57+
log.Debug("Parse failed", "path", p, "error", err, "duration", time.Since(parseStart))
4758
return err
4859
}
60+
parseTime := time.Since(parseStart)
61+
log.Debug("Parse completed", "path", p, "duration", parseTime)
4962

5063
if stack.Valid() {
5164
return stacks.AddStack(stack)
@@ -54,6 +67,9 @@ func LoadStacks(dir string) (*schema.Stacks, error) {
5467
return nil
5568
})
5669

70+
totalTime := time.Since(start)
71+
log.Debug("LoadStacks completed", "total_duration", totalTime)
72+
5773
return stacks, err
5874
}
5975

0 commit comments

Comments
 (0)