Skip to content

Commit 2f95f4a

Browse files
aknyshautofix-ci[bot]claudeosterman
authored
Allow locals to access settings, vars, and env from the same file. Add locals design patterns. Add Atmos YAML functions support in locals (#1994)
* fix locals * fix locals * [autofix.ci] apply automated fixes * address comments * improve docs, add example for `locals` * [autofix.ci] apply automated fixes * address comments * update docs * address comments, update docs, add tests for locals example, add locals design patterns, add blog post * address comments, update docs, add tests * address comments, update docs, add tests * address comments, update docs, add tests * address comments, update docs, add tests * address comments * update docs * update docs * fix: Align diagram with numbered steps and add missing periods - Update mermaid diagram to show template processing as step 4 after merge - Remove step 3 from per-file boxes (templates processed after merge) - Add periods to list items in troubleshooting section for consistency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * update docs * update docs * update docs * update docs and example * update docs and example * locals with Atmos YAML functions, update docs, add tests, add blog posts * update roadmap * address comments, add tests * update docs * docs: Condense locals documentation by 60% for clarity (#2000) - Reduced stacks/locals.mdx from 827 to 331 lines (60% cut) - Consolidated Configuration Scopes (3 examples → 1 comprehensive example) - Moved Processing Order diagram to <details> block ("How does processing work?") - Deleted redundant "Complete Example" section, rely on "Try It" embed instead - Removed duplicate explanations of file-scoped isolation across sections - Moved debugging output examples to <details> block - Condensed error handling section and best practices - Removed "Scope Merging", "Limitations", "When to Use Each" sections as redundant - Reduced examples/locals/README.md from 155 to 35 lines (77% cut) - Aligned with standard example README pattern (demo-stacks/README.md style) - Removed 60-line "Example Output" section - Removed 40-line "Key Concepts" section duplicating main docs - Fixed broken documentation link (/core-concepts/stacks/locals → /stacks/locals) Locals is a minor feature with key gotchas. Documentation now appropriately sized. Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> * update tests * address comments --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <erik@cloudposse.com>
1 parent 1eeae7d commit 2f95f4a

File tree

45 files changed

+2568
-350
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2568
-350
lines changed

NOTICE

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ APACHE 2.0 LICENSED DEPENDENCIES
2323

2424
- cloud.google.com/go/auth
2525
License: Apache-2.0
26-
URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.17.0/auth/LICENSE
26+
URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.18.0/auth/LICENSE
2727

2828
- cloud.google.com/go/auth/oauth2adapt
2929
License: Apache-2.0
@@ -307,7 +307,7 @@ APACHE 2.0 LICENSED DEPENDENCIES
307307

308308
- github.com/googleapis/enterprise-certificate-proxy/client
309309
License: Apache-2.0
310-
URL: https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.3.7/LICENSE
310+
URL: https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.3.9/LICENSE
311311

312312
- github.com/gosimple/unidecode
313313
License: Apache-2.0
@@ -507,15 +507,15 @@ APACHE 2.0 LICENSED DEPENDENCIES
507507

508508
- google.golang.org/genproto/googleapis/rpc
509509
License: Apache-2.0
510-
URL: https://github.com/googleapis/go-genproto/blob/97cd9d5aeac2/googleapis/rpc/LICENSE
510+
URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/googleapis/rpc/LICENSE
511511

512512
- google.golang.org/grpc
513513
License: Apache-2.0
514514
URL: https://github.com/grpc/grpc-go/blob/v1.78.0/LICENSE
515515

516516
- gopkg.in/ini.v1
517517
License: Apache-2.0
518-
URL: https://github.com/go-ini/ini/blob/v1.67.0/LICENSE
518+
URL: https://github.com/go-ini/ini/blob/v1.67.1/LICENSE
519519

520520
- gopkg.in/yaml.v2
521521
License: Apache-2.0
@@ -788,11 +788,11 @@ BSD LICENSED DEPENDENCIES
788788

789789
- google.golang.org/api
790790
License: BSD-3-Clause
791-
URL: https://github.com/googleapis/google-api-go-client/blob/v0.258.0/LICENSE
791+
URL: https://github.com/googleapis/google-api-go-client/blob/v0.260.0/LICENSE
792792

793793
- google.golang.org/api/internal/third_party/uritemplates
794794
License: BSD-3-Clause
795-
URL: https://github.com/googleapis/google-api-go-client/blob/v0.258.0/internal/third_party/uritemplates/LICENSE
795+
URL: https://github.com/googleapis/google-api-go-client/blob/v0.260.0/internal/third_party/uritemplates/LICENSE
796796

797797
- google.golang.org/protobuf
798798
License: BSD-3-Clause
@@ -1074,7 +1074,7 @@ MIT LICENSED DEPENDENCIES
10741074

10751075
- github.com/bmatcuk/doublestar/v4
10761076
License: MIT
1077-
URL: https://github.com/bmatcuk/doublestar/blob/v4.9.1/LICENSE
1077+
URL: https://github.com/bmatcuk/doublestar/blob/v4.9.2/LICENSE
10781078

10791079
- github.com/catppuccin/go
10801080
License: MIT

errors/errors.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -743,10 +743,11 @@ var (
743743
ErrNoOptionsAvailable = errors.New("no options available")
744744

745745
// Locals-related errors.
746-
ErrLocalsInvalidType = errors.New("locals must be a map")
747-
ErrLocalsCircularDep = errors.New("circular dependency in locals")
748-
ErrLocalsDependencyExtract = errors.New("failed to extract dependencies for local")
749-
ErrLocalsResolution = errors.New("failed to resolve local")
746+
ErrLocalsInvalidType = errors.New("locals must be a map")
747+
ErrLocalsCircularDep = errors.New("circular dependency in locals")
748+
ErrLocalsDependencyExtract = errors.New("failed to extract dependencies for local")
749+
ErrLocalsResolution = errors.New("failed to resolve local")
750+
ErrLocalsYamlFunctionFailed = errors.New("failed to process YAML function in local")
750751

751752
// Source provisioner errors.
752753
ErrSourceProvision = errors.New("source provisioning failed")

examples/locals/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Example: Locals
2+
3+
Reduce repetition and build computed values using file-scoped locals.
4+
5+
Learn more about [Locals](https://atmos.tools/stacks/locals).
6+
7+
## What You'll See
8+
9+
- **Basic locals**: Define reusable values within a file
10+
- **Dependency resolution**: Locals can reference other locals
11+
- **Context access**: Locals can access `settings`, `vars`, and `env` from the same file
12+
- **File-scoped isolation**: Each stack file has independent locals
13+
14+
## Try It
15+
16+
```shell
17+
cd examples/locals
18+
19+
# View resolved locals for the dev stack
20+
atmos describe locals -s dev
21+
22+
# View resolved locals for a specific component
23+
atmos describe locals myapp -s dev
24+
25+
# Compare dev vs prod
26+
atmos describe locals myapp -s prod
27+
```
28+
29+
## Key Files
30+
31+
| File | Purpose |
32+
|------|---------|
33+
| `stacks/deploy/dev.yaml` | Development stack with locals |
34+
| `stacks/deploy/prod.yaml` | Production stack with locals |
35+
| `components/terraform/myapp/main.tf` | Terraform component |

examples/locals/atmos.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Atmos Locals Example
2+
3+
base_path: "."
4+
5+
components:
6+
terraform:
7+
base_path: "components/terraform"
8+
apply_auto_approve: false
9+
deploy_run_init: true
10+
init_run_reconfigure: true
11+
auto_generate_backend_file: false
12+
13+
stacks:
14+
base_path: "stacks"
15+
included_paths:
16+
- "deploy/**/*"
17+
name_template: "{{ .vars.stage }}"
18+
19+
templates:
20+
settings:
21+
enabled: true
22+
sprig:
23+
enabled: true
24+
gomplate:
25+
enabled: true
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Mock component for locals demo.
2+
#
3+
# This component outputs the variables it receives, allowing you to see
4+
# how locals are resolved and passed to components.
5+
6+
variable "name" {
7+
type = string
8+
description = "Application name"
9+
}
10+
11+
variable "environment" {
12+
type = string
13+
description = "Environment name"
14+
}
15+
16+
variable "full_name" {
17+
type = string
18+
description = "Full application name (computed from locals)"
19+
}
20+
21+
variable "tags" {
22+
type = map(string)
23+
description = "Resource tags (computed from locals)"
24+
default = {}
25+
}
26+
27+
output "name" {
28+
description = "Application name"
29+
value = var.name
30+
}
31+
32+
output "environment" {
33+
description = "Environment name"
34+
value = var.environment
35+
}
36+
37+
output "full_name" {
38+
description = "Full application name"
39+
value = var.full_name
40+
}
41+
42+
output "tags" {
43+
description = "Resource tags"
44+
value = var.tags
45+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Development Environment Stack
2+
#
3+
# This stack demonstrates locals for reducing repetition and building
4+
# computed values. Locals are file-scoped (cannot be accessed from other files).
5+
6+
settings:
7+
version: v1
8+
team: platform
9+
10+
vars:
11+
stage: dev
12+
13+
# Locals can reference other locals, settings, and vars.
14+
locals:
15+
# Basic values
16+
namespace: acme
17+
environment: development
18+
19+
# Reference other locals
20+
name_prefix: "{{ .locals.namespace }}-{{ .locals.environment }}"
21+
22+
# Access settings
23+
app_version: "{{ .settings.version }}"
24+
25+
# Access vars
26+
stage_name: "{{ .vars.stage }}"
27+
28+
# Build complex computed values
29+
full_name: "{{ .locals.name_prefix }}-{{ .locals.stage_name }}"
30+
31+
# Maps work too
32+
default_tags:
33+
Namespace: "{{ .locals.namespace }}"
34+
Environment: "{{ .locals.environment }}"
35+
Team: "{{ .settings.team }}"
36+
ManagedBy: Atmos
37+
38+
# Components use the resolved locals
39+
components:
40+
terraform:
41+
myapp:
42+
vars:
43+
name: "{{ .locals.namespace }}"
44+
environment: "{{ .locals.environment }}"
45+
full_name: "{{ .locals.full_name }}"
46+
tags: "{{ .locals.default_tags }}"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Production Environment Stack
2+
#
3+
# This stack shows locals with different values for production.
4+
# Each file has its own isolated locals scope.
5+
6+
settings:
7+
version: v2
8+
team: platform
9+
10+
vars:
11+
stage: prod
12+
13+
locals:
14+
namespace: acme
15+
environment: production
16+
17+
# Same pattern, different values
18+
name_prefix: "{{ .locals.namespace }}-{{ .locals.environment }}"
19+
full_name: "{{ .locals.name_prefix }}-{{ .vars.stage }}"
20+
21+
# Production-specific tags
22+
default_tags:
23+
Namespace: "{{ .locals.namespace }}"
24+
Environment: "{{ .locals.environment }}"
25+
Team: "{{ .settings.team }}"
26+
ManagedBy: Atmos
27+
CostCenter: production
28+
29+
components:
30+
terraform:
31+
myapp:
32+
vars:
33+
name: "{{ .locals.namespace }}"
34+
environment: "{{ .locals.environment }}"
35+
full_name: "{{ .locals.full_name }}"
36+
tags: "{{ .locals.default_tags }}"

go.mod

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.sum

Lines changed: 13 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/exec/describe_locals.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ func processStackFileForLocals(
358358
return &stackFileLocalsResult{}, nil
359359
}
360360

361-
localsCtx, err := ProcessStackLocals(atmosConfig, rawConfig, filePath)
361+
localsCtx, err := ProcessStackLocals(atmosConfig, rawConfig, filePath, stackName)
362362
if err != nil {
363363
return &stackFileLocalsResult{Found: true}, fmt.Errorf("failed to process locals for stack %s: %w", stackFileName, err)
364364
}

0 commit comments

Comments
 (0)